Skip to content

Commit

Permalink
Better safe function execution. More error codes.
Browse files Browse the repository at this point in the history
  • Loading branch information
s-baumann committed Jan 3, 2019
1 parent 26a7852 commit 7604437
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 56 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,11 @@ There are a few errors that can result in a InvalidInputOrOutputOfIteration term
* NoError - This indicates no error. You should never see this unless developing in the package as a function evaluation without an error will not cause a InvalidInputOrOutputOfIteration termination that causes the FunctionEvaluationResult struct to be returned.
* ErrorExecutingFunction - This indicates that there was an error evaluating the function with the given inputs. This will occur for instance if you try to evaluate sqrt.(x) at x = [-1.0] or 1/x at x = [0.0]. This may be solved by changing acceleration algorithm so that it does not try a vector which causes errors in the function. It may also be possible to reparameterise the function so that any vector is a valid input to the function.
* LengthOfOutputNotSameAsInput - A function taking an N-dimensional vector is not returning an N-dimensional vector.
* MissingsDetected - A function is returning an output vector containing missing values.
* NAsDetected - A function is returning an output vector containing NaN values.
* InfsDetected - A function is returning an output vector containing Inf values. While mathematically there is nothing wrong wtih this (Inf is a fixedpoint of the f(x) = x!), the algorithms of this package are not going to be useful in this case and hence it is not supported.
* InputMissingsDetected - A function is returning an input vector containing missing values.
* InputNAsDetected - A function is returning an input vector containing NaN values.
* InputInfsDetected - A function is returning an input vector containing Inf values. While mathematically there is nothing wrong with this (Inf is a fixedpoint of the f(x) = x!), the algorithms of this package are not going to be useful in this case and hence it is not supported.
* OutputMissingsDetected - A function is returning an output vector containing missing values.
* OutputNAsDetected - A function is returning an output vector containing NaN values.
* OutputInfsDetected - A function is returning an output vector containing Inf values. While mathematically there is nothing wrong with this (like for InputInfsDetected) it is not supported.

Together this error handling system should handle any errors gracefully without raising an ErrorException. ErrorExceptions are avoided so that the Inputs and Outputs from previous iterates are retained and the search for a fixed point can be resumed without interruption. If an ErrorException does occur while using fixed_point please raise an issue in github because this is not expected.
9 changes: 6 additions & 3 deletions src/0_Structs_And_Enums.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
NoError = 0
ErrorExecutingFunction = 1
LengthOfOutputNotSameAsInput = 2
MissingsDetected = 3
NAsDetected = 4
InfsDetected = 5 # This is not always an error. The function f(x) = x has a fuxed point at infinity. In practical
InputMissingsDetected = 3
InputNAsDetected = 4
InputInfsDetected = 5
OutputMissingsDetected = 6
OutputNAsDetected = 7
OutputInfsDetected = 8 # This is not always an error. The function f(x) = x has a fuxed point at infinity. In practical
# settings however an infinite fixed point is unlikely to be the desired one. Also the algorithms here would not
# likely work in the infinity case.
end
Expand Down
85 changes: 41 additions & 44 deletions src/1_MainFunctions.jl
Original file line number Diff line number Diff line change
@@ -1,48 +1,55 @@
"""
create_safe_function_executor(Func::Function)
execute_function_safely(Func::Function, x::Array{Float64,1})
This function creates a function that executes the function for which a fixed point is sought. It is a helper function that is not exported.
### Takes
* Func - The function input to fixed_point
* x - The point at which to evaluate the function.
### Returns
A FunctionEvaluationResult containing the following fields:
* Input_ - The input
* Output_ - The output of the FunctionExecutor. May be missing if function could not complete without error.
* Error_ - A enum of type FP_FunctionEvaluationError representing what error occured.
### Examples
Func(x) = sqrt(x)
FunctionExecutor = create_safe_function_executor(Func)
FunctionExecutor([-1.0,0.0,1.0])
FunctionExecutor([Missing(),0.0,1.0])
FunctionExecutor([7.0,0.0,1.0])
FunctionExecutor([NaN,0.0,1.0])
FunctionExecutor([Inf,0.0,1.0])
FunctionExecutor(-1.0)
FunctionExecutor(Missing())
FunctionExecutor(1.0)
FunctionExecutor(NaN)
FunctionExecutor(Inf)
execute_function_safely(Func, [-1.0,0.0,1.0])
execute_function_safely(Func,[Missing(),0.0,1.0])
execute_function_safely(Func,[7.0,0.0,1.0])
execute_function_safely(Func,[NaN,0.0,1.0])
execute_function_safely(Func,[Inf,0.0,1.0])
execute_function_safely(Func,-1.0)
execute_function_safely(Func,Missing())
execute_function_safely(Func,1.0)
execute_function_safely(Func,NaN)
execute_function_safely(Func,Inf)
"""
function create_safe_function_executor(Func::Function)
function CheckResultAndReturn_not_elementwise(x)
tf_result = Array
try
tf_result = Func(x)
catch
return FunctionEvaluationResult(x, missing, ErrorExecutingFunction)
end
if sum(ismissing.(tf_result)) > 0
return FunctionEvaluationResult(x, tf_result, MissingsDetected)
elseif sum(isnan.(tf_result)) > 0
return FunctionEvaluationResult(x, tf_result, NAsDetected)
elseif sum(isinf.(tf_result)) > 0
return FunctionEvaluationResult(x, tf_result, InfsDetected)
elseif (length(tf_result) != length(x))
return FunctionEvaluationResult(x, tf_result, LengthOfOutputNotSameAsInput)
else
return FunctionEvaluationResult(x, tf_result, NoError)
end
function execute_function_safely(Func::Function, x::Array{Float64,1})
# Check input
if sum(ismissing.(x)) > 0
return FunctionEvaluationResult(x, missing, InputMissingsDetected)
elseif sum(isnan.(x)) > 0
return FunctionEvaluationResult(x, missing, InputNAsDetected)
elseif sum(isinf.(x)) > 0
return FunctionEvaluationResult(x, missing, InputInfsDetected)
end
# Run function.
tf_result = Array
try
tf_result = Func(x)
catch
return FunctionEvaluationResult(x, missing, ErrorExecutingFunction)
end
# Check Output and return.
if sum(ismissing.(tf_result)) > 0
return FunctionEvaluationResult(x, tf_result, OutputMissingsDetected)
elseif sum(isnan.(tf_result)) > 0
return FunctionEvaluationResult(x, tf_result, OutputNAsDetected)
elseif sum(isinf.(tf_result)) > 0
return FunctionEvaluationResult(x, tf_result, OutputInfsDetected)
elseif (length(tf_result) != length(x))
return FunctionEvaluationResult(x, tf_result, LengthOfOutputNotSameAsInput)
else
return FunctionEvaluationResult(x, tf_result, NoError)
end
return CheckResultAndReturn_not_elementwise
end

"""
Expand Down Expand Up @@ -137,13 +144,10 @@ function fixed_point(func::Function, Inputs::Array{Float64, 2}; Outputs::Array{F
SimpleStartIndex = 1
end
end
# Create safe function Executor
SafeFunction = create_safe_function_executor(func)

LengthOfArray = size(Inputs)[1]
# Do an initial run if no runs have been done:
if isempty(Outputs)
ExecutedFunction = SafeFunction(Inputs[:,1])
ExecutedFunction = execute_function_safely(func, Inputs[:,1])
if ExecutedFunction.Error_ != NoError
return FixedPointResults(Inputs, Outputs, InvalidInputOrOutputOfIteration; FailedEvaluation_ = ExecutedFunction)
end
Expand Down Expand Up @@ -180,7 +184,7 @@ function fixed_point(func::Function, Inputs::Array{Float64, 2}; Outputs::Array{F
print(lpad("",42))
end

ExecutedFunction = SafeFunction(NewInputFunctionReturn)
ExecutedFunction = execute_function_safely(func, NewInputFunctionReturn)
if ExecutedFunction.Error_ != NoError
return FixedPointResults(Inputs, Outputs, InvalidInputOrOutputOfIteration; ConvergenceVector_ = vec(ConvergenceVector), FailedEvaluation_ = ExecutedFunction)
end
Expand All @@ -200,13 +204,6 @@ function fixed_point(func::Function, Inputs::Array{Float64, 2}; Outputs::Array{F
return FixedPointResults(Inputs, Outputs, Finish; ConvergenceVector_ = vec(ConvergenceVector))
end








"""
This function takes the previous inputs and outputs from the fixed_point function and determines what vector to try next in seeking a fixed point.
### Takes
Expand Down
3 changes: 2 additions & 1 deletion src/FixedPointAcceleration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export put_together_without_jumps, create_safe_function_executor # Auxillery fun
# Exporting enums
export FixedPointAccelerationAlgorithm, Simple, Anderson, Aitken, Newton, VEA, SEA, MPE, RRE # Algorithms
export InvalidReplacement, NoAction, ReplaceElements, ReplaceVector # Strategies for handling invalids in proposed new inputs.
export FP_FunctionEvaluationError, NoError, ErrorExecutingFunction, LengthOfOutputNotSameAsInput, MissingsDetected, NAsDetected, InfsDetected # Errors in evaluating
export FP_FunctionEvaluationError, NoError, ErrorExecutingFunction, LengthOfOutputNotSameAsInput, InputMissingsDetected
export InputNAsDetected, InputInfsDetected, OutputMissingsDetected, OutputNAsDetected, OutputInfsDetected # Errors in evaluating
export TerminationCondition, ReachedConvergenceThreshold, ReachedMaxIter, InvalidInputOrOutputOfIteration # Termination Conditions
end
7 changes: 3 additions & 4 deletions test/BoundsError.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ fp = fixed_point(simple_vector_function, Inputs; Algorithm = Anderson)
# iterations for a while to fix this.
fp.TerminationCondition_ == InvalidInputOrOutputOfIteration
fp.FailedEvaluation_.Error_ == ErrorExecutingFunction
fp
fp = fixed_point(simple_vector_function, fp; Algorithm = Simple, MaxIter = 7)
fp.TerminationCondition_ == ReachedMaxIter
fp = fixed_point(simple_vector_function, fp; Algorithm = Anderson)
Expand All @@ -23,7 +22,7 @@ function funcfunc(x::Array{Float64,1})
end
Inputs = [4.0,1.0]
fp = fixed_point(funcfunc, Inputs; Algorithm = Anderson)
fp.FailedEvaluation_.Error_ == NAsDetected
fp.FailedEvaluation_.Error_ == OutputNAsDetected
# Testing Output of Missing
function funcfunc(x::Array{Float64,1})
if abs(x[1] - 4.0) < 1e-12
Expand All @@ -33,7 +32,7 @@ function funcfunc(x::Array{Float64,1})
end
Inputs = [4.0,1.0]
fp = fixed_point(funcfunc, Inputs; Algorithm = Anderson)
fp.FailedEvaluation_.Error_ == MissingsDetected
fp.FailedEvaluation_.Error_ == OutputMissingsDetected
# Testing Output of Inf
function funcfunc(x::Array{Float64,1})
if abs(x[1] - 4.0) < 1e-12
Expand All @@ -43,7 +42,7 @@ function funcfunc(x::Array{Float64,1})
end
Inputs = [4.0,1.0]
fp = fixed_point(funcfunc, Inputs; Algorithm = Anderson)
fp.FailedEvaluation_.Error_ == InfsDetected
fp.FailedEvaluation_.Error_ == OutputInfsDetected
# Testing Output of wrong size
function funcfunc(x::Array{Float64,1})
if abs(x[1] - 4.0) < 1e-12
Expand Down
2 changes: 1 addition & 1 deletion test/ReplaceInvalidsTesting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function funcfunc(x::Array{Float64,1})
end
Inputs = [19.0,10.0]
fp = fixed_point(funcfunc, Inputs; Algorithm = Aitken)
fp.FailedEvaluation_.Error_ == InfsDetected
fp.FailedEvaluation_.Error_ == InputInfsDetected
fp.FailedEvaluation_.Input_[1] == -Inf
!isinf(fp.FailedEvaluation_.Input_[2])
# Now fixing with replace element
Expand Down

0 comments on commit 7604437

Please sign in to comment.