Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/function_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -652,8 +652,10 @@ _eval_fd_impl(
"Evaluate the `PiecewiseLinearData` or `PiecewiseStepData` at a given x-coordinate"
function (fd::Union{PiecewiseLinearData, PiecewiseStepData})(x::Real)
lb, ub = get_domain(fd)
(x < lb || x > ub) &&
# defend against floating point precision issues at the boundaries.
((lb <= x <= ub) || isapprox(x, lb) || isapprox(x, ub)) ||
throw(ArgumentError("x=$x is outside the domain [$lb, $ub]"))
x = clamp(x, lb, ub)
x_coords = get_x_coords(fd)
y_coords = get_y_coords(fd)
i_leq = searchsortedlast(x_coords, x) # uses binary search!
Expand Down
9 changes: 7 additions & 2 deletions src/value_curve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ InputOutputCurve{T}(
) where {(T <: Union{QuadraticFunctionData, LinearFunctionData, PiecewiseLinearData})} =
InputOutputCurve{T}(function_data, nothing)

"""
Evaluate the `InputOutputCurve` at a given input value `x`.
"""
(ioc::InputOutputCurve)(x::Real) = get_function_data(ioc)(x)

"""
An incremental (or 'marginal') curve, relating the production quantity to the derivative of
cost: `y = f'(x)`. Can be used, for instance, in the representation of a [`CostCurve`](@ref)
Expand All @@ -62,7 +67,7 @@ IncrementalCurve(function_data, initial_input) =
IncrementalCurve{T}(
function_data,
initial_input,
) where {(T <: Union{QuadraticFunctionData, LinearFunctionData, PiecewiseLinearData})} =
) where {(T <: Union{LinearFunctionData, PiecewiseStepData})} =
IncrementalCurve{T}(function_data, initial_input, nothing)

"""
Expand All @@ -87,7 +92,7 @@ AverageRateCurve(function_data, initial_input) =
AverageRateCurve{T}(
function_data,
initial_input,
) where {(T <: Union{QuadraticFunctionData, LinearFunctionData, PiecewiseLinearData})} =
) where {(T <: Union{LinearFunctionData, PiecewiseStepData})} =
AverageRateCurve{T}(function_data, initial_input, nothing)

"Get the `initial_input` field of this `ValueCurve` (not defined for `InputOutputCurve`)"
Expand Down
29 changes: 29 additions & 0 deletions test/test_cost_functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,32 @@ end
) ==
IS.LinearCurve(10.0, 7.0)
end

@testset "Test prohibited FunctionData types" begin
# Incremental and Average Rate curves only support
# linear and piecewise step function data.
q_fd = IS.QuadraticFunctionData(1, 2, 3)
pwl_fd = IS.PiecewiseLinearData([(x = 0.0, y = 1.0), (x = 1.0, y = 2.0)])
@test_throws MethodError IS.IncrementalCurve(q_fd, 0.0)
@test_throws MethodError IS.AverageRateCurve(q_fd, 0.0)
@test_throws MethodError IS.IncrementalCurve(pwl_fd, 0.0)
@test_throws MethodError IS.AverageRateCurve(pwl_fd, 0.0)
end

@testset "Test InputOutputCurve evaluation" begin
io_quadratic = IS.InputOutputCurve(IS.QuadraticFunctionData(1, 2, 3))
@test io_quadratic(0.0) == 3.0
@test io_quadratic(1.0) == 6.0
@test io_quadratic(2.0) == 11.0

io_linear = IS.InputOutputCurve(IS.LinearFunctionData(3, 2))
@test io_linear(0.0) == 2.0
@test io_linear(1.0) == 5.0
@test io_linear(2.0) == 8.0

pwl = IS.PiecewiseLinearData([(x = 1, y = 3), (x = 3, y = 7), (x = 5, y = 11)])
io_piecewise = IS.InputOutputCurve(pwl)
@test io_piecewise(1.0) == 3.0
@test io_piecewise(3.0) == 7.0
@test io_piecewise(5.0) == 11.0
end
20 changes: 20 additions & 0 deletions test/test_function_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -689,3 +689,23 @@ end
compact_plain_ans
end
end

@testset "Test piecewise domain checking" begin
pwl = IS.PiecewiseStepData([1, 3, 5], [8, 10])

# floating point inputs
@test_throws ArgumentError pwl(0.5)
@test_throws ArgumentError pwl(5.5)
pwl(2.5)

# non floating point inputs
@test_throws ArgumentError pwl(1 // 2)
@test_throws ArgumentError pwl(5 + 1 // 2)
pwl(5 // 2)

# floating point precision edge cases (should not error)
@assert isapprox(1 - eps() / 2, 1)
@assert isapprox(5 + eps() / 2, 5)
pwl(1 - eps() / 2)
pwl(5 + eps() / 2)
end
Loading