11module EvaluateEquationModule
22
3- import .. EquationModule: Node
3+ import .. EquationModule: Node, string_tree
44import .. OperatorEnumModule: OperatorEnum, GenericOperatorEnum
55import .. UtilsModule: @return_on_false , is_bad_array, vals
66import .. EquationUtilsModule: is_constant
@@ -47,8 +47,12 @@ function eval(current_node)
4747The bulk of the code is for optimizations and pre-emptive NaN/Inf checks,
4848which speed up evaluation significantly.
4949
50- # Returns
50+ # Arguments
51+ - `tree::Node`: The root node of the tree to evaluate.
52+ - `cX::AbstractMatrix{T}`: The input data to evaluate the tree on.
53+ - `operators::OperatorEnum`: The operators used in the tree.
5154
55+ # Returns
5256- `(output, complete)::Tuple{AbstractVector{T}, Bool}`: the result,
5357 which is a 1D array, as well as if the evaluation completed
5458 successfully (true/false). A `false` complete means an infinity
@@ -461,19 +465,51 @@ function eval(current_node)
461465 return current_node.operator(eval(current_node.left_child), eval(current_node.right_child))
462466```
463467
464-
468+ # Arguments
469+ - `tree::Node`: The root node of the tree to evaluate.
470+ - `cX::AbstractArray{T,N}`: The input data to evaluate the tree on.
471+ - `operators::GenericOperatorEnum`: The operators used in the tree.
472+ - `throw_errors::Bool=true`: Whether to throw errors
473+ if they occur during evaluation. Otherwise,
474+ MethodErrors will be caught before they happen and
475+ evaluation will return `nothing`,
476+ rather than throwing an error. This is useful in cases
477+ where you are unsure if a particular tree is valid or not,
478+ and would prefer to work with `nothing` as an output.
465479
466480# Returns
467-
468481- `(output, complete)::Tuple{Any, Bool}`: the result,
469482 as well as if the evaluation completed successfully (true/false).
470483 If evaluation failed, `nothing` will be returned for the first argument.
471484 A `false` complete means an operator was called on input types
472485 that it was not defined for.
473486"""
474487function eval_tree_array (
475- tree:: Node{T1} , cX:: AbstractArray{T2,N} , operators:: GenericOperatorEnum
476- ) where {T1,T2,N}
488+ tree:: Node , cX:: AbstractArray , operators:: GenericOperatorEnum ; throw_errors:: Bool = true
489+ )
490+ ! throw_errors && return _eval_tree_array (tree, cX, operators, Val (false ))
491+ try
492+ return _eval_tree_array (tree, cX, operators, Val (true ))
493+ catch e
494+ tree_s = string_tree (tree, operators)
495+ error_msg = " Failed to evaluate tree $(tree_s) ."
496+ if isa (e, MethodError)
497+ error_msg *= (
498+ " Note that you can efficiently skip MethodErrors" *
499+ " beforehand by passing `throw_errors=false` to " *
500+ " `eval_tree_array`."
501+ )
502+ end
503+ throw (ErrorException (error_msg))
504+ end
505+ end
506+
507+ function _eval_tree_array (
508+ tree:: Node{T1} ,
509+ cX:: AbstractArray{T2,N} ,
510+ operators:: GenericOperatorEnum ,
511+ :: Val{throw_errors} ,
512+ ) where {T1,T2,N,throw_errors}
477513 if tree. degree == 0
478514 if tree. constant
479515 return (tree. val:: T1 ), true
@@ -485,27 +521,33 @@ function eval_tree_array(
485521 end
486522 end
487523 elseif tree. degree == 1
488- return deg1_eval (tree, cX, vals[tree. op], operators)
524+ return deg1_eval (tree, cX, vals[tree. op], operators, Val (throw_errors) )
489525 else
490- return deg2_eval (tree, cX, vals[tree. op], operators)
526+ return deg2_eval (tree, cX, vals[tree. op], operators, Val (throw_errors) )
491527 end
492528end
493529
494- function deg1_eval (tree, cX, :: Val{op_idx} , operators:: GenericOperatorEnum ) where {op_idx}
530+ function deg1_eval (
531+ tree, cX, :: Val{op_idx} , operators:: GenericOperatorEnum , :: Val{throw_errors}
532+ ) where {op_idx,throw_errors}
495533 left, complete = eval_tree_array (tree. l, cX, operators)
496- ! complete && return nothing , false
534+ ! throw_errors && ! complete && return nothing , false
497535 op = operators. unaops[op_idx]
498- ! hasmethod (op, Tuple{typeof (left)}) && return nothing , false
536+ ! throw_errors && ! hasmethod (op, Tuple{typeof (left)}) && return nothing , false
499537 return op (left), true
500538end
501539
502- function deg2_eval (tree, cX, :: Val{op_idx} , operators:: GenericOperatorEnum ) where {op_idx}
540+ function deg2_eval (
541+ tree, cX, :: Val{op_idx} , operators:: GenericOperatorEnum , :: Val{throw_errors}
542+ ) where {op_idx,throw_errors}
503543 left, complete = eval_tree_array (tree. l, cX, operators)
504- ! complete && return nothing , false
544+ ! throw_errors && ! complete && return nothing , false
505545 right, complete = eval_tree_array (tree. r, cX, operators)
506- ! complete && return nothing , false
546+ ! throw_errors && ! complete && return nothing , false
507547 op = operators. binops[op_idx]
508- ! hasmethod (op, Tuple{typeof (left),typeof (right)}) && return nothing , false
548+ ! throw_errors &&
549+ ! hasmethod (op, Tuple{typeof (left),typeof (right)}) &&
550+ return nothing , false
509551 return op (left, right), true
510552end
511553
0 commit comments