API
API Documentation of OptiFloat.jl
optifloat(expr::Expr, T::Type, batchsize::Int, steps::Int, interval_compatible::Bool)
The main function of OptiFloat.jl. Optimizes a floating point expression and returns a result object which contains an improved expression.
Example
julia> using OptiFloat
julia> expr = :(sqrt(x+1) - sqrt(x))
julia> optifloat(expr; T=Float16, batchsize=100, steps=1, interval_compatible=false)
For more convenient usage, see @optifloat
Arguments
expr::Expr
: The floating point expression that should be optimized.T::Type{<:AbstractFloat}
: Floating point type that the expression should be evaluated on.batchsize::Int
: Number of samples that OptiFloat will compute errors for. The samples are computed vialogsample
such that only samples which do not causeDomainError
s/overflows are used.steps::Int
: Number of timessearch_candidates!
is called.interval_compatible::Bool
: Iffalse
the improved function only accepts normal numbers otherwise theresult.improved
will be an expression that acceptsInterval
s. In the latter case you have to loadIntervalArithmetic
, otherwiseeval(result.improved)
will fail.
Returns
An OptiFloatResult
.
@optifloat expr kws...
The main macro of OptiFloat.jl. Optimizes a floating point expression and returns a result object which contains an improved expression. Accepts the same keyword arguments as optifloat
.
Examples
julia> using OptiFloat
julia> g = @optifloat sqrt(x+1) - sqrt(x) T=Float16 batchsize=1000
julia> g(Float16(3730))
Float16(0.00819)
Internals
Rules that are used to generate new candidate expressions.
Rules that are used to simplify generated candidate expressions. This is a subset of REWRITE_THEORY
.
Candidate{E<:Expression,A<:AbstractArray,F<:Function}
Holds an original and a candidate expression, as well as their biterror
and an indication if the candidate has already been used in search_candidates!
(used: ✓, unused: ⊚). Should only be constructed via one of the two constructors below:
Candidate(candidate::Expr, original::Expr, points::AbstractMatrix)
Candidate(candidate::Expr, points::AbstractMatrix)
(if candidate and original are the same)
OptiFloatResult{O<:Expr,I<:Expr,C<:Candidate,R<:PiecewiseRegime}
Fields
original::Expr
: The original expression that was attempted to be optimized.improved::Expr
: The (potentially) improved expression.original_candidate::Candidate
: TheCandidate
of the original expression. This struct includes the error on the sampled points.improved_regimes::PiecewiseRegime
: The struct that was used to generateimproved
.
parse_expression(T::Type{<:AbstractFloat}, expr::Expr; kws...)
Parse a Julia Expr
to a dynamic Expression
that can be used to efficiently compute local_biterror
s. Convenience overload of DynamicExpressions.parse_expression
.
biterror(x::T, y::T) where {T}
The biterror
is defined as the logarithm of the ULP-distance (unit at the last place) biterror(x,y) = log2(ulpdistance(x,y))
. For the example above to approximately 11 bits:
julia> using OptiFloat
julia> f(x) = sqrt(x+1) - sqrt(x)
julia> g(x) = 1 / (sqrt(x+1) + sqrt(x))
julia> x = Float16(3730)
julia> OptiFloat.biterror(f(x), g(x))
infer_regimes(candidates::Vector{<:Candidate}, feature::Int, points::Matrix{T}; kws...)
Pick as few candidates and their corresponding good regimes to define a PiecewiseRegime
that represents an expression that performs well on all points
.
function local_biterror(
tree::Node{T},
ops::AbstractOperatorEnum,
X::AbstractMatrix{T};
accum=default_accum
) where {T}
Compute the error of the root node in tree
. The children are evaluated exactly, such that only the error of the root node is returned. local_biterrors
computes the local error for all nodes in the tree.
function local_biterror(
tree::Node{T},
ops::AbstractOperatorEnum,
X::AbstractMatrix{T};
accum=default_accum
) where {T}
Compute the error per node/operation in tree
. For each node, the children are evaluated exactly, such that only the error of the current node is returned. local_biterrors
computes the error for all nodes in the tree.
local_biterrors(expr::Expression, x::AbstractArray)
Recursively call local_biterror
on all nodes in expr
and return the local error for each node.
logsample(expr::Expression, batchsize::Int; eval_exact=true)
Sample valid inputs to expr
. If eval_exact=false
expr
is evaluated with BigFloat
s so samples might be generated that cause overflow in the original floating point type of expr
.
optifloat(expr::Expr, T::Type, batchsize::Int, steps::Int, interval_compatible::Bool)
The main function of OptiFloat.jl. Optimizes a floating point expression and returns a result object which contains an improved expression.
Example
julia> using OptiFloat
julia> expr = :(sqrt(x+1) - sqrt(x))
julia> optifloat(expr; T=Float16, batchsize=100, steps=1, interval_compatible=false)
For more convenient usage, see @optifloat
Arguments
expr::Expr
: The floating point expression that should be optimized.T::Type{<:AbstractFloat}
: Floating point type that the expression should be evaluated on.batchsize::Int
: Number of samples that OptiFloat will compute errors for. The samples are computed vialogsample
such that only samples which do not causeDomainError
s/overflows are used.steps::Int
: Number of timessearch_candidates!
is called.interval_compatible::Bool
: Iffalse
the improved function only accepts normal numbers otherwise theresult.improved
will be an expression that acceptsInterval
s. In the latter case you have to loadIntervalArithmetic
, otherwiseeval(result.improved)
will fail.
Returns
An OptiFloatResult
.
print_report(io::IO, original::Candidate, rs::PiecewiseRegime; rm_ansi=false)
Output a report including a copy-pasteable function representing the PiecewiseRegime
.
Generate samples from samplefn
that yield finite results when called with testfn
:
x = samplefn(T, inputsize)
y = testfn(x) <-- add to samples if isfinite(y)
search_candidates!(candidates::Vector{<:Candidate}, points::Matrix{T}) where {T}
Try to find better candidate expressions than the ones that are already present in candidates
. The first unused candidate will be attempted to improve and new candidate expression are added to candidates
. Once a candidate is picked, this function goes through the following steps:
Given an initial expression
candidate
, compute thelocal_biterror
of every subexpression and pick the subexpressionsub_expr
with the worst error for further analysis.Recursively rewrite the
sub_expr
based on a set of rewrite rules, generating a number of new candidates.Simplify the candidates via equality saturation (implemented in Metatheory.jl)
Compute error of new candidates and add every candidate that performs better on any of the
points
to the existing list.
@optifloat expr kws...
The main macro of OptiFloat.jl. Optimizes a floating point expression and returns a result object which contains an improved expression. Accepts the same keyword arguments as optifloat
.
Examples
julia> using OptiFloat
julia> g = @optifloat sqrt(x+1) - sqrt(x) T=Float16 batchsize=1000
julia> g(Float16(3730))
Float16(0.00819)