diff --git a/Project.toml b/Project.toml index 95a458cb16..b15c4569be 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "SciMLBase" uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462" authors = ["Chris Rackauckas and contributors"] -version = "1.98.1" +version = "1.99.0" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" diff --git a/src/SciMLBase.jl b/src/SciMLBase.jl index 011dfd690e..220df92ff8 100644 --- a/src/SciMLBase.jl +++ b/src/SciMLBase.jl @@ -759,9 +759,9 @@ export isinplace export solve, solve!, init, discretize, symbolic_discretize -export LinearProblem, - NonlinearProblem, IntervalNonlinearProblem, - IntegralProblem, SampledIntegralProblem, OptimizationProblem +export LinearProblem, NonlinearProblem, IntervalNonlinearProblem, + IntegralProblem, SampledIntegralProblem, OptimizationProblem, + NonlinearLeastSquaresProblem export DiscreteProblem, ImplicitDiscreteProblem export SteadyStateProblem, SteadyStateSolution diff --git a/src/problems/basic_problems.jl b/src/problems/basic_problems.jl index cd057eba50..8ef27e5bf3 100644 --- a/src/problems/basic_problems.jl +++ b/src/problems/basic_problems.jl @@ -312,6 +312,85 @@ function NonlinearProblem(prob::AbstractODEProblem) NonlinearProblem{isinplace(prob)}(prob.f, prob.u0, prob.p) end +@doc doc""" +Defines a nonlinear least squares problem. + +## Mathematical Specification of a Nonlinear Least Squares Problem + +To define a Nonlinear Problem, you simply need to give the function ``f`` which defines the +nonlinear system: + +```math +\underset{x}{\min} \| f(x, p) \| +``` + +and an initial guess ``u_0`` for the minimization problem. ``f`` should be specified as +``f(u, p)`` (or in-place as ``f(du, u, p)``), and ``u_0``` should be an AbstractArray (or +number) whose geometry matches the desired geometry of ``u``. Note that we are not limited +to numbers or vectors for ``u_0``; one is allowed to provide ``u_0`` as arbitrary +matrices / higher-dimension tensors as well. + +## Problem Type + +### Constructors + +```julia +NonlinearLeastSquaresProblem(f::NonlinearFunction, u0, p=NullParameters(); kwargs...) +NonlinearLeastSquaresProblem{isinplace}(f, u0, p=NullParameters(); kwargs...) +``` + +`isinplace` optionally sets whether the function is in-place or not. This is +determined automatically, but not inferred. + +Parameters are optional, and if not given, then a `NullParameters()` singleton +will be used, which will throw nice errors if you try to index non-existent +parameters. + +For specifying Jacobians and mass matrices, see the +[NonlinearFunctions](@ref nonlinearfunctions) page. + +### Fields + +* `f`: The function in the problem. +* `u0`: The initial guess for the solution. +* `p`: The parameters for the problem. Defaults to `NullParameters`. +* `kwargs`: The keyword arguments passed on to the solvers. +""" +struct NonlinearLeastSquaresProblem{uType, isinplace, P, F, K} <: + AbstractNonlinearProblem{uType, isinplace} + f::F + u0::uType + p::P + kwargs::K + + @add_kwonly function NonlinearLeastSquaresProblem{iip}(f::AbstractNonlinearFunction{ + iip}, u0, p = NullParameters(); kwargs...) where {iip} + warn_paramtype(p) + return new{typeof(u0), iip, typeof(p), typeof(f), typeof(kwargs)}(f, u0, p, kwargs) + end + + function NonlinearLeastSquaresProblem{iip}(f, u0, p = NullParameters()) where {iip} + return NonlinearLeastSquaresProblem{iip}(NonlinearFunction{iip}(f), u0, p) + end +end + +TruncatedStacktraces.@truncate_stacktrace NonlinearLeastSquaresProblem 2 1 + +""" +$(SIGNATURES) + +Define a nonlinear least squares problem using an instance of +[`AbstractNonlinearFunction`](@ref AbstractNonlinearFunction). +""" +function NonlinearLeastSquaresProblem(f::AbstractNonlinearFunction, u0, + p = NullParameters(); kwargs...) + return NonlinearLeastSquaresProblem{isinplace(f)}(f, u0, p; kwargs...) +end + +function NonlinearLeastSquaresProblem(f, u0, p = NullParameters(); kwargs...) + return NonlinearLeastSquaresProblem(NonlinearFunction(f), u0, p; kwargs...) +end + @doc doc""" Defines an integral problem. @@ -434,7 +513,7 @@ struct SampledIntegralProblem{Y, X, K} <: AbstractIntegralProblem{false} @add_kwonly function SampledIntegralProblem(y::AbstractArray, x::AbstractVector; dim = ndims(y), kwargs...) - @assert dim <= ndims(y) "The integration dimension `dim` is larger than the number of dimensions of the integrand `y`" + @assert dim<=ndims(y) "The integration dimension `dim` is larger than the number of dimensions of the integrand `y`" @assert length(x)==size(y, dim) "The integrand `y` must have the same length as the sampling points `x` along the integrated dimension." @assert axes(x, 1)==axes(y, dim) "The integrand `y` must obey the same indexing as the sampling points `x` along the integrated dimension." new{typeof(y), typeof(x), typeof(kwargs)}(y, x, dim, kwargs) diff --git a/src/remake.jl b/src/remake.jl index 9d310f07a8..1772f333a7 100644 --- a/src/remake.jl +++ b/src/remake.jl @@ -246,6 +246,38 @@ function remake(prob::NonlinearProblem; end end + +""" + remake(prob::NonlinearLeastSquaresProblem; f = missing, u0 = missing, p = missing, + kwargs = missing, _kwargs...) + +Remake the given `NonlinearLeastSquaresProblem`. +""" +function remake(prob::NonlinearLeastSquaresProblem; f = missing, u0 = missing, p = missing, + kwargs = missing, _kwargs...) + if p === missing && u0 === missing + p, u0 = prob.p, prob.u0 + else # at least one of them has a value + if p === missing + p = prob.p + end + if u0 === missing + u0 = prob.u0 + end + end + + if f === missing + f = prob.f + end + + if kwargs === missing + return NonlinearLeastSquaresProblem{isinplace(prob)}(; f, u0, p, prob.kwargs..., + _kwargs...) + else + return NonlinearLeastSquaresProblem{isinplace(prob)}(; f, u0, p, kwargs...) + end +end + # overloaded in MTK to intercept symbolic remake function process_p_u0_symbolic(prob, p, u0) if typeof(prob) <: Union{AbstractDEProblem, OptimizationProblem, NonlinearProblem}