@@ -230,9 +230,9 @@ function count_nodes(tree::AbstractNode; break_sharing=Val(false))
230230end
231231
232232"""
233- foreach(f::Function, tree::AbstractNode)
233+ foreach(f::Function, tree::AbstractNode; break_sharing::Val=Val(false) )
234234
235- Apply a function to each node in a tree.
235+ Apply a function to each node in a tree without returning the results .
236236"""
237237function foreach (
238238 f:: F , tree:: AbstractNode ; break_sharing:: Val = Val (false )
@@ -244,7 +244,7 @@ function foreach(
244244end
245245
246246"""
247- filter_map(filter_fnc::Function, map_fnc::Function, tree::AbstractNode, result_type::Type)
247+ filter_map(filter_fnc::Function, map_fnc::Function, tree::AbstractNode, result_type::Type, break_sharing::Val=Val(false) )
248248
249249A faster equivalent to `map(map_fnc, filter(filter_fnc, tree))`
250250that avoids the intermediate allocation. However, using this requires
@@ -286,7 +286,7 @@ function filter_map!(
286286end
287287
288288"""
289- filter(f::Function, tree::AbstractNode)
289+ filter(f::Function, tree::AbstractNode; break_sharing::Val=Val(false) )
290290
291291Filter nodes of a tree, returning a flat array of the nodes for which the function returns `true`.
292292"""
@@ -299,7 +299,7 @@ function collect(tree::AbstractNode; break_sharing::Val=Val(false))
299299end
300300
301301"""
302- map(f::Function , tree::AbstractNode, result_type::Type{RT}=Nothing)
302+ map(f::F , tree::AbstractNode, result_type::Type{RT}=Nothing; break_sharing::Val=Val(false)) where {F<:Function,RT}
303303
304304Map a function over a tree and return a flat array of the results in depth-first order.
305305Pre-specifying the `result_type` of the function can be used to avoid extra allocations.
@@ -314,6 +314,11 @@ function map(
314314 end
315315end
316316
317+ """
318+ count(f::F, tree::AbstractNode; init=0, break_sharing::Val=Val(false)) where {F<:Function}
319+
320+ Count the number of nodes in a tree for which the function returns `true`.
321+ """
317322function count (
318323 f:: F , tree:: AbstractNode ; init= 0 , break_sharing:: Val = Val (false )
319324) where {F<: Function }
@@ -327,22 +332,44 @@ function count(
327332 ) + init
328333end
329334
335+ """
336+ sum(f::Function, tree::AbstractNode; init=0, return_type=Undefined, f_on_shared=_default_shared_aggregation, break_sharing::Val=Val(false)) where {F<:Function}
337+
338+ Sum the results of a function over a tree. For graphs with shared nodes
339+ such as `GraphNode`, the function `f_on_shared` is called on the result
340+ of each shared node. This is used to avoid double-counting shared nodes (default
341+ behavior).
342+ """
330343function sum (
331344 f:: F ,
332345 tree:: AbstractNode ;
333346 init= 0 ,
334347 return_type= Undefined,
335- f_on_shared= (c, is_shared) -> is_shared ? ( false * c) : c ,
348+ f_on_shared= _default_shared_aggregation ,
336349 break_sharing:: Val = Val (false ),
337350) where {F<: Function }
338351 if preserve_sharing (typeof (tree))
339352 @assert typeof (return_type) != = Undefined " Must specify `return_type` as a keyword argument to `sum` if `preserve_sharing` is true."
340353 end
341354 return tree_mapreduce (f, + , tree, return_type; f_on_shared, break_sharing) + init
342355end
356+ function _default_shared_aggregation (c, is_shared)
357+ return is_shared ? (false * c) : c
358+ end
359+
360+ """
361+ all(f::Function, tree::AbstractNode)
343362
363+ Reduce a flag function over a tree, returning `true` if the
364+ function returns `true` for all nodes, `false` otherwise.
365+ """
344366all (f:: F , tree:: AbstractNode ) where {F<: Function } = ! any (t -> ! @inline (f (t)), tree)
345367
368+ """
369+ mapreduce(f::Function, op::Function, tree::AbstractNode; return_type, f_on_shared, break_sharing)
370+
371+ Map a function over a tree and aggregate the result using an operator `op`.
372+ """
346373function mapreduce (
347374 f:: F ,
348375 op:: G ,
@@ -369,28 +396,32 @@ function length(tree::AbstractNode; break_sharing::Val=Val(false))
369396 return count_nodes (tree; break_sharing)
370397end
371398
372- function hash (tree:: AbstractExpressionNode{T} ) where {T}
399+ """
400+ hash(tree::AbstractExpressionNode{T}[, h::UInt]; break_sharing::Val=Val(false)) where {T}
401+
402+ Compute a hash of a tree. This will compute a hash differently
403+ if nodes are shared in a tree. This is ignored if `break_sharing` is set to `Val(true)`.
404+ """
405+ function hash (tree:: AbstractExpressionNode{T} , h:: UInt = zero (UInt); break_sharing:: Val = Val (false )) where {T}
373406 return tree_mapreduce (
374- t -> t. constant ? hash ((0 , t. val:: T )) : hash ((1 , t. feature)),
375- t -> hash ((t. degree + 1 , t. op)),
376- (n... ) -> hash (n),
407+ t -> t. constant ? hash ((0 , t. val:: T ), h ) : hash ((1 , t. feature), h ),
408+ t -> hash ((t. degree + 1 , t. op), h ),
409+ (n... ) -> hash (n, h ),
377410 tree,
378- UInt64 ;
411+ UInt ;
379412 f_on_shared= (cur_hash, is_shared) ->
380- is_shared ? hash ((:shared , cur_hash)) : cur_hash,
413+ is_shared ? hash ((:shared , cur_hash), h) : cur_hash,
414+ break_sharing,
381415 )
382416end
383417
384418"""
385- copy_node(tree::AbstractExpressionNode)
419+ copy_node(tree::AbstractExpressionNode; break_sharing::Val=Val(false) )
386420
387421Copy a node, recursively copying all children nodes.
388422This is more efficient than the built-in copy.
389423
390- id_map is a map from `objectid(tree)` to `copy(tree)`.
391- We check against the map before making a new copy; otherwise
392- we can simply reference the existing copy.
393- [Thanks to Ted Hopp.](https://stackoverflow.com/questions/49285475/how-to-copy-a-full-non-binary-tree-including-loops)
424+ If `break_sharing` is set to `Val(true)`, sharing in a tree will be ignored.
394425"""
395426function copy_node (
396427 tree:: N ; break_sharing:: Val = Val (false )
@@ -409,12 +440,20 @@ function copy_node(
409440 )
410441end
411442
443+ """
444+ copy(tree::AbstractExpressionNode; break_sharing::Val=Val(false))
445+
446+ Copy a node, recursively copying all children nodes.
447+ This is more efficient than the built-in copy.
448+
449+ If `break_sharing` is set to `Val(true)`, sharing in a tree will be ignored.
450+ """
412451function copy (tree:: AbstractExpressionNode ; break_sharing:: Val = Val (false ))
413452 return copy_node (tree; break_sharing)
414453end
415454
416455"""
417- convert(::Type{AbstractExpressionNode{T1}}, n::AbstractExpressionNode{T2}) where {T1,T2}
456+ convert(::Type{<: AbstractExpressionNode{T1}}, n::AbstractExpressionNode{T2}) where {T1,T2}
418457
419458Convert a `AbstractExpressionNode{T2}` to a `AbstractExpressionNode{T1}`.
420459This will recursively convert all children nodes to `AbstractExpressionNode{T1}`,
0 commit comments