Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
39d8f9f
Update Fishing example docs
wenwen0231 Apr 17, 2025
a7e7953
Adjust unit test of fishing example to test output values within tole…
wenwen0231 Apr 21, 2025
cfe7cc0
Update Hanging Chain example docs
wenwen0231 Apr 21, 2025
30a2779
Update Jennings example docs
wenwen0231 Apr 21, 2025
6006d2c
Added unit tests to examples (excluding pandemic control)
wenwen0231 Apr 21, 2025
33444f9
Merge branch 'infiniteopt:master' into docu
wenwen0231 May 7, 2025
a455690
Update tolerance to 1E-06
wenwen0231 May 7, 2025
6d96753
Merge branch 'docu' of https://github.com/wenwen0231/InfiniteOpt.jl i…
wenwen0231 May 7, 2025
f5d91c4
Add InfiniteInterpolate with basic value function extension based on …
wenwen0231 May 29, 2025
278c370
Add argument so that interpolation method is user defined
wenwen0231 May 30, 2025
b338a1c
Add logic that throws an error for unsupported interpolation methods …
wenwen0231 May 30, 2025
b51f3bf
Added unit tests for catching irregular grid method errors and checki…
wenwen0231 Jun 2, 2025
17cbc1a
Include InfiniteInterpolate test in runtests.jl
wenwen0231 Jun 2, 2025
f510146
Add InfiniteInterpolate with basic value function extension based on …
wenwen0231 May 29, 2025
bf1b25c
Add argument so that interpolation method is user defined
wenwen0231 May 30, 2025
2bdd77d
Add logic that throws an error for unsupported interpolation methods …
wenwen0231 May 30, 2025
74b15df
Added unit tests for catching irregular grid method errors and checki…
wenwen0231 Jun 2, 2025
7c700b2
Include InfiniteInterpolate test in runtests.jl
wenwen0231 Jun 2, 2025
2be1cf2
Merge branch 'interpolate' of https://github.com/wenwen0231/InfiniteO…
wenwen0231 Jun 2, 2025
4828775
Add docstring to InfiniteInterpolate ext & unit test for unsupported …
wenwen0231 Jun 11, 2025
a1afd54
Add InfiniteInterpolate with basic value function extension based on …
wenwen0231 May 29, 2025
8c89781
Add argument so that interpolation method is user defined
wenwen0231 May 30, 2025
d473250
Add logic that throws an error for unsupported interpolation methods …
wenwen0231 May 30, 2025
1481120
Added unit tests for catching irregular grid method errors and checki…
wenwen0231 Jun 2, 2025
917454c
Include InfiniteInterpolate test in runtests.jl
wenwen0231 Jun 2, 2025
7aa7896
Add InfiniteInterpolate with basic value function extension based on …
wenwen0231 May 29, 2025
005e467
Added unit tests for catching irregular grid method errors and checki…
wenwen0231 Jun 2, 2025
7d42c8f
Include InfiniteInterpolate test in runtests.jl
wenwen0231 Jun 2, 2025
256464c
Add docstring to InfiniteInterpolate ext & unit test for unsupported …
wenwen0231 Jun 11, 2025
03431fa
Add InfiniteInterpolate to Project.toml + use InfiniteInteprolate val…
wenwen0231 Jun 17, 2025
afce04f
Change Ipopt to mock optimizer in InfiniteInterpolate test case
wenwen0231 Jun 17, 2025
2787874
Add semi-infinite, point, finite & derivative variables to InfiniteIn…
wenwen0231 Jun 20, 2025
eb61c56
Add a small example on using InfiniteInterpolate in docs > src > guid…
wenwen0231 Jun 20, 2025
c5064dd
Merge branch 'interpolate' of https://github.com/wenwen0231/InfiniteO…
wenwen0231 Jun 20, 2025
ff172d1
Add Interpolations.jl to [extras] and [targets] in Project.toml
wenwen0231 Jul 29, 2025
f5ea77c
Move Interpolations.jl import statement from runtests.jl to InfiniteI…
wenwen0231 Aug 2, 2025
80dc659
Update results.md doc about type piracy issue with InfiniteInterpolate
wenwen0231 Aug 2, 2025
9d2cf53
Merge branch 'interpolate' of https://github.com/wenwen0231/InfiniteO…
wenwen0231 Aug 2, 2025
850df0e
Merge branch 'master' into interpolate
pulsipher Aug 13, 2025
29a2374
Change Matrix datatype -> Array in InfiniteInterpolate wrapper function
wenwen0231 Aug 14, 2025
ceb8611
Merge branch 'infiniteopt:master' into interpolate
wenwen0231 Aug 14, 2025
81c420d
Adjust documentation for InfiniteInterpolate in guide/result.md and I…
wenwen0231 Aug 19, 2025
c579c81
Add orthogonal collocation points to InfiniteInterpolate test case
wenwen0231 Aug 26, 2025
0053366
Add degree + fallback functions to InfiniteInterpolate extension; upd…
wenwen0231 Aug 26, 2025
f508abd
Merge branch 'infiniteopt:master' into interpolate
wenwen0231 Aug 26, 2025
0f5c960
Adjust InfiniteInterpolate documentation
wenwen0231 Aug 26, 2025
4889111
Adjust make.jl to load in InfiniteInterpolate extension
wenwen0231 Aug 27, 2025
5cc1f13
Adjust hyperlinks to InfiniteInterpolate extension in technical manual
wenwen0231 Aug 27, 2025
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
10 changes: 9 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"

[weakdeps]
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"

[extensions]
InfiniteInterpolate = "Interpolations"

[compat]
DataStructures = "0.14.2 - 0.18, 0.19"
Distributions = "0.19 - 0.25"
Expand All @@ -20,12 +26,14 @@ JuMP = "1.18"
MutableArithmetics = "1"
Reexport = "0.2, 1"
julia = "^1.6"
Interpolations = "0.16"

[extras]
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"

[targets]
test = ["Pkg", "Test", "Random", "Suppressor"]
test = ["Pkg", "Test", "Random", "Suppressor", "Interpolations"]
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"

[compat]
Distributions = "0.25"
Expand All @@ -23,3 +24,4 @@ JuMP = "1.23"
Literate = "2.18"
Plots = "1"
SpecialFunctions = "2"
Interpolations = "0.16"
5 changes: 3 additions & 2 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Documenter, InfiniteOpt, Distributions, Literate, Random
using Documenter, InfiniteOpt, Distributions, Literate, Random, Interpolations

if !@isdefined(EXAMPLE_DIR)
const EXAMPLE_DIR = joinpath(@__DIR__, "src", "examples")
Expand Down Expand Up @@ -96,7 +96,8 @@ makedocs(;
],
sitename = "InfiniteOpt.jl",
authors = "Joshua Pulsipher and Weiqi Zhang",
modules = [InfiniteOpt],
modules = [InfiniteOpt, isdefined(Base, :get_extension) ? Base.get_extension(InfiniteOpt, :InfiniteInterpolate) :
InfiniteOpt.InfiniteInterpolate,],
checkdocs = :none,
linkcheck = true,
linkcheck_ignore = [r"https://www.youtube.com/.*"],
Expand Down
20 changes: 14 additions & 6 deletions docs/src/examples/Optimal Control/hovercraft.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,21 @@ end)
# Optimize the model:
optimize!(m)

# Extract the results:
x_opt = value.(x);
# Extract the results. The [`InfiniteInterpolate`](@ref infiniteInterpolate) extension can be used to get a smooth interpolated function for x, which is invoked when both the `Interpolations` and `InfiniteOpt` packages are imported. Here, cubic splines and linear were chosen as the interpolation methods for x1 and x2, respectively:
using Interpolations
xFunc = value.(x, (cubic_spline_interpolation, linear_interpolation));

# Query our interpolated function for the values of x1 and x2:
tvals = LinRange(0, 60, 100)
x1Vals = xFunc[1](tvals)
x2Vals = xFunc[2](tvals);

# Plot the results:
using Plots
scatter(xw[1,:], xw[2,:], label = "Waypoints", background_color = :transparent)
plot!(x_opt[1], x_opt[2], label = "Trajectory")
scatter(xw[1,:], xw[2,:], label = "Waypoints")
xlabel!("x_1")
ylabel!("x_2")
plot!(x1Vals, x2Vals, label = "Trajectory")

# That's it, now we have our optimal trajectory!

Expand All @@ -79,8 +85,10 @@ using Test
tol = 1E-6
@test termination_status(m) == MOI.LOCALLY_SOLVED
@test has_values(m)
@test x_opt isa Vector{<:Vector{<:Real}}
@test x1Vals isa Vector{<:Real}
@test x2Vals isa Vector{<:Real}
@test isapprox(objective_value(m), 0.043685293177035435, atol=tol)
@test isapprox(value(u[1])[end], -0.010503853944039986, atol=tol)
@test isapprox(value(u[2])[end], 0.005456780217220367, atol=tol)

@test isapprox(x1Vals[15], 1.3837274935883543, atol=tol)
@test isapprox(x2Vals[15], 1.6392615199958938, atol=tol)
44 changes: 43 additions & 1 deletion docs/src/guide/result.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ parameter dependencies.
This also holds true for many other methods in `InfiniteOpt`. For example,
adding the dot also vectorizes `dual` and `set_binary`.

We can also query the dual of a constraint via
We can query the dual of a constraint via
[`dual`](@ref JuMP.dual(::InfOptConstraintRef)) if a model has duals available
as indicated by [`has_duals`](@ref):
```jldoctest results
Expand Down Expand Up @@ -184,6 +184,48 @@ These again all have a 1-to-1 correspondence.
parameters, an n-dimensional array will typically be returned
whose dimensions correspond to the supports of the infinite parameters.

## InfiniteInterpolate queries
We can also get a continuous representation of a variable as an interpolations object from the `Interpolations.jl` package. This is based on the [`InfiniteInterpolate`](@ref infiniteInterpolate) extension, which is automatically loaded in when both `InfiniteOpt` and `Interpolations` are imported. The current supported methods are `linear_interpolation`, `constant_interpolation` and `cubic_spline_interpolation`.
```jldoctest results
julia> using Interpolations

julia> yFunc = value(y, linear_interpolation)
10-element extrapolate(interpolate((::Vector{Float64},), ::Vector{Float64}, Gridded(Linear())), Throw()) with element type Float64:
42.0
20.999999995627107
20.999999995628606
20.999999995628603
20.999999995628592
20.999999995628603
20.999999995634035
20.999999995620904
20.99999999562204
20.9999999956286

julia> yFunc(5.12)
20.9999999956286
```
Alternatively, we can specify the degree of interpolation with `Linear()`, `Constant()` or `Cubic()`. This will call the corresponding interpolation method.
```jldoctest results
julia> yFunc = value(y, Linear()) # equivalent to value(y, linear_interpolation)
10-element extrapolate(interpolate((::Vector{Float64},), ::Vector{Float64}, Gridded(Linear())), Throw()) with element type Float64:
42.0
20.999999995627107
20.999999995628606
20.999999995628603
20.999999995628592
20.999999995628603
20.999999995634035
20.999999995620904
20.99999999562204
20.9999999956286

julia> yFunc(5.12)
20.9999999956286
```
!!! warning
There is a type piracy conflict between JuMP and OffsetArrays (a dependency of Interpolations.jl). As a result, type piracy issues may arise when Interpolations is loaded in. Please keep this in mind when using the InfiniteInterpolate extension.

## Termination Queries
Termination queries are those that question about how the infinite model was
solved and what its optimized state entails. Programmatically, such queries on
Expand Down
6 changes: 6 additions & 0 deletions docs/src/manual/result.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ JuMP.reduced_cost(::GeneralVariableRef)
JuMP.optimizer_index(::GeneralVariableRef)
```

## [InfiniteInterpolate](@id infiniteInterpolate)
```@docs
JuMP.value(::GeneralVariableRef, ::Union{typeof(Interpolations.constant_interpolation), typeof(Interpolations.cubic_spline_interpolation), typeof(Interpolations.linear_interpolation)})
JuMP.value(::GeneralVariableRef, ::Interpolations.Degree)
```

## Constraints
```@docs
JuMP.has_duals(::InfiniteModel)
Expand Down
100 changes: 100 additions & 0 deletions ext/InfiniteInterpolate.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
module InfiniteInterpolate

import JuMP
import InfiniteOpt as infOpt
import Interpolations as IP

const _irregularGridMethods = Union{typeof(IP.linear_interpolation),
typeof(IP.constant_interpolation)}

const _convenienceConstructors = Union{typeof(IP.linear_interpolation),
typeof(IP.constant_interpolation),
typeof(IP.cubic_spline_interpolation)}

"""
JuMP.value(vref::GeneralVariableRef, method::Union{typeof(Interpolations.constant_interpolation), typeof(Interpolations.cubic_spline_interpolation), typeof(Interpolations.linear_interpolation)}; [kwargs...])

Extend `JuMP.value` to return `vref` as an interpolation object from Interpolations.jl, where the `method` argument specifies the interpolation method to be used.
The currently supported methods are `linear_interpolation`, `constant_interpolation` and `cubic_spline_interpolation`.

**Example**
```julia-repl
julia> zFunc = value(z, cubic_spline_interpolation)
julia> zFunc(5.4)
42.0
```
"""
function JuMP.value(vref::infOpt.GeneralVariableRef, interpMethod::_convenienceConstructors; kwargs...)
infOpt._check_result_is_current(JuMP.owner_model(vref), JuMP.value)

# Get infinite parameter references for which the variable depends on
prefs = infOpt.parameter_refs(vref)

if isempty(prefs)
# If no infinite parameters, return the value directly
return infOpt._get_value(vref, infOpt._index_type(vref); kwargs...)
else
# Get the parameter supports
Vparams = []
for pref in prefs
# If user defined irregular grid points for supports, throw an error if the specified method doesn't support it
suppsLabel = first(infOpt.core_object(pref).supports)[2]
if !(infOpt.UniformGrid in suppsLabel) && !(interpMethod isa _irregularGridMethods)
throw(ArgumentError("Interpolation method $(interpMethod) does not support irregular grids for supports. Please specify a uniform grid or choose a different interpolation method."))
end

paramVals = infOpt._get_value(pref, infOpt._index_type(pref); kwargs...)
numSupps = length(paramVals)
if interpMethod isa _irregularGridMethods
# Can directly pass in a vector of support values, which may be irregularly spaced
push!(Vparams, paramVals)
else
# Create an equidistant range for support values
paramRange = LinRange(paramVals[1], paramVals[end], numSupps)
push!(Vparams, paramRange)
end
end

# Ensure Vparams is a tuple for interpolation
Vparams = Tuple(Vparams)

# Get the variable supports
Vsupps = infOpt._get_value(vref, infOpt._index_type(vref); kwargs...)

# Pass the parameter and variable values to interpolation function
varFunc = interpMethod(Vparams, Vsupps)
return varFunc
end
end

"""
JuMP.value(vref::GeneralVariableRef, degree::Interpolations.Degree; [kwargs...])

Extend `JuMP.value` to return `vref` as an interpolation object from Interpolations.jl, where the `degree` argument specifies the degree of interpolation. The corresponding interpolation method is called depending on the degree.
The currently supported degrees are `Linear()`, `Constant()` and `Cubic()`.

**Example**
```julia-repl
julia> zFunc = value(z, Cubic())
julia> zFunc(5.4)
42.0
```
"""
function JuMP.value(vref::infOpt.GeneralVariableRef, degree::IP.Degree; kwargs...)
if degree == IP.Linear()
return JuMP.value(vref, IP.linear_interpolation; kwargs...)
elseif degree == IP.Constant()
return JuMP.value(vref, IP.constant_interpolation; kwargs...)
elseif degree == IP.Cubic()
return JuMP.value(vref, IP.cubic_spline_interpolation; kwargs...)
else
throw(ArgumentError("Unsupported interpolation degree type: $(degree). Supported degree types are: Linear(), Constant(), and Cubic()."))
end
end

# Fallback for unsupported interpolation types
function JuMP.value(vref::infOpt.GeneralVariableRef, method::IP.InterpolationType; kwargs...)
throw(ArgumentError("Unsupported interpolation type: $(method). Supported interpolation types are: Linear(), Constant(), and Cubic()."))
end

end
Loading
Loading