@@ -177,6 +177,14 @@ function DEFAULT_OBSERVED_NO_TIME(sym, u, p)
177177 error (" Indexing symbol $sym is unknown." )
178178end
179179
180+ function DEFAULT_POLYNOMIALIZE (u, p)
181+ return u
182+ end
183+
184+ function DEFAULT_UNPOLYNOMIALIZE (u, p)
185+ return (u,)
186+ end
187+
180188function Base. summary (io:: IO , prob:: AbstractSciMLFunction )
181189 type_color, no_color = get_colorizers (io)
182190 print (io,
@@ -1741,6 +1749,108 @@ struct NonlinearFunction{iip, specialize, F, TMM, Ta, Tt, TJ, JVP, VJP, JP, SP,
17411749 initialization_data:: ID
17421750end
17431751
1752+ """
1753+ $(TYPEDEF)
1754+
1755+ A representation of a polynomial nonlinear system of equations given by
1756+
1757+ ```math
1758+ 0 = f(polynomialize(u, p), p)
1759+ ```
1760+
1761+ Designed to be used for solving with HomotopyContinuation.
1762+
1763+ ## Constructor
1764+
1765+ $(TYPEDSIGNATURES)
1766+
1767+ Note that only the function `f` is required. This function should be given as `f!(du,u,p)`
1768+ or `du = f(u,p)`. See the section on `iip` for more details on in-place vs out-of-place
1769+ handling.
1770+
1771+ To provide the Jacobian function etc, `f` must be a [`NonlinearFunction`](@ref) with the
1772+ required fields populated.
1773+
1774+ ## iip: In-Place vs Out-Of-Place
1775+
1776+ For more details on this argument, see the ODEFunction documentation.
1777+
1778+ ## specialize: Controlling Compilation and Specialization
1779+
1780+ For more details on this argument, see the ODEFunction documentation.
1781+
1782+ ## Fields
1783+
1784+ The fields of the `HomotopyNonlinearFunction` type directly match the names of the inputs.
1785+
1786+ $(FIELDS)
1787+ """
1788+ struct HomotopyNonlinearFunction{iip, specialize, F, P, Q, D} < :
1789+ SciMLBase. AbstractSciMLFunction{iip}
1790+ """
1791+ The polynomial function `f`. Stored as a `NonlinearFunction{iip, specialize}`. If not
1792+ provided to the constructor as a `NonlinearFunction`, it will be appropriately wrapped.
1793+ """
1794+ f:: F
1795+ """
1796+ The nonlinear system may be a polynomial of non-polynomial functions. For example,
1797+ ```math
1798+ sin^2(x^2) + 2sin(x^2) + 1 = 0
1799+ log(x + y) ^ 3 = 0.5
1800+ ```
1801+
1802+ is a polynomial in `[sin(x^2), log(x + y)]`. To allow for such systems, `polynomialize`
1803+ converts the state vector of the original system (termed as an "original space" vector)
1804+ to the state vector of the polynomial system (termed as a "polynomial space" vector).
1805+ In the above example, it will be the function:
1806+
1807+ ```julia
1808+ functon polynomialize(u, p)
1809+ x, y = u
1810+ return [sin(x^2), log(x + y)]
1811+ end
1812+ ```
1813+
1814+ We refer to `[x, y]` as being in "original space" and `[sin(x^2), log(x + y)]` as being
1815+ in "polynomial space".
1816+
1817+ This defaults to a function which returns `u` as-is.
1818+ """
1819+ polynomialize:: P
1820+ """
1821+ The inverse operation of `polynomialize`.
1822+
1823+ This function takes as input a vector `u′` in "polynomial space" and returns a collection of
1824+ vectors `uᵢ ∀ i ∈ {1..n}` in "original space" such that `polynomialize(uᵢ, p) == u′ ∀ i`.
1825+ A collection is returned since the mapping may not be bijective. For periodic functions
1826+ which have infinite such vectors `uᵢ`, it is up to the user to choose which ones to return.
1827+
1828+ In the aforementioned example in `polynomialize`, this function will be:
1829+
1830+ ```julia
1831+ function unpolynomialize(u, p)
1832+ a, b = u
1833+ return [
1834+ [sqrt(asin(a)), exp(b) - sqrt(asin(a))],
1835+ [-sqrt(asin(a)), exp(b) + sqrt(asin(a))],
1836+ ]
1837+ end
1838+ ```
1839+
1840+ There are of course an infinite number of such functions due to the presence of `sin`.
1841+ This example chooses to return the roots in the interval `[-π/2, π/2]`.
1842+ """
1843+ unpolynomialize:: Q
1844+ """
1845+ A function of the form `denominator(u, p) -> denoms` where `denoms` is an array of
1846+ denominator terms which cannot be zero. This is useful when `f` represents the
1847+ numerator of a rational function. Roots of `f` which cause any of the values in
1848+ `denoms` to be below a threshold will be excluded. Note that here `u` must be in
1849+ "polynomial space".
1850+ """
1851+ denominator:: D
1852+ end
1853+
17441854"""
17451855$(TYPEDEF)
17461856"""
@@ -3899,6 +4009,33 @@ function NonlinearFunction(f; kwargs...)
38994009end
39004010NonlinearFunction (f:: NonlinearFunction ; kwargs... ) = f
39014011
4012+ function HomotopyNonlinearFunction {iip, specialize} (f;
4013+ polynomialize = __has_polynomialize (f) ? f. polynomialize : DEFAULT_POLYNOMIALIZE,
4014+ unpolynomialize = __has_unpolynomialize (f) ? f. unpolynomialize :
4015+ DEFAULT_UNPOLYNOMIALIZE,
4016+ denominator = __has_denominator (f) ? f. denominator : Returns (())
4017+ ) where {iip, specialize}
4018+ f = f isa NonlinearFunction ? f : NonlinearFunction {iip, specialize} (f)
4019+
4020+ if specialize === NoSpecialize
4021+ HomotopyNonlinearFunction {iip, specialize, Any, Any, Any, Any} (
4022+ f, polynomialize, unpolynomialize, denominator)
4023+ else
4024+ HomotopyNonlinearFunction{iip, specialize, typeof (f), typeof (polynomialize),
4025+ typeof (unpolynomialize), typeof (denominator)}(
4026+ f, polynomialize, unpolynomialize, denominator)
4027+ end
4028+ end
4029+
4030+ function HomotopyNonlinearFunction {iip} (f; kwargs... ) where {iip}
4031+ HomotopyNonlinearFunction {iip, FullSpecialize} (f; kwargs... )
4032+ end
4033+ HomotopyNonlinearFunction {iip} (f:: HomotopyNonlinearFunction ; kwargs... ) where {iip} = f
4034+ function HomotopyNonlinearFunction (f; kwargs... )
4035+ HomotopyNonlinearFunction {isinplace(f, 3), FullSpecialize} (f; kwargs... )
4036+ end
4037+ HomotopyNonlinearFunction (f:: HomotopyNonlinearFunction ; kwargs... ) = f
4038+
39024039function IntervalNonlinearFunction {iip, specialize} (f;
39034040 analytic = __has_analytic (f) ?
39044041 f. analytic :
@@ -4500,6 +4637,9 @@ function __has_initializeprobpmap(f)
45004637 has_initialization_data (f) && isdefined (f. initialization_data, :initializeprobpmap )
45014638end
45024639__has_initialization_data (f) = isdefined (f, :initialization_data )
4640+ __has_polynomialize (f) = isdefined (f, :polynomialize )
4641+ __has_unpolynomialize (f) = isdefined (f, :unpolynomialize )
4642+ __has_denominator (f) = isdefined (f, :denominator )
45034643
45044644# compatibility
45054645has_invW (f:: AbstractSciMLFunction ) = false
@@ -4528,6 +4668,9 @@ end
45284668function has_initialization_data (f)
45294669 __has_initialization_data (f) && f. initialization_data != = nothing
45304670end
4671+ has_polynomialize (f) = __has_polynomialize (f) && f. polynomialize != = nothing
4672+ has_unpolynomialize (f) = __has_unpolynomialize (f) && f. unpolynomialize != = nothing
4673+ has_denominator (f) = __has_denominator (f) && f. denominator != = nothing
45314674
45324675function has_syms (f:: AbstractSciMLFunction )
45334676 if __has_syms (f)
@@ -4601,6 +4744,13 @@ has_Wfact_t(f::JacobianWrapper) = has_Wfact_t(f.f)
46014744has_paramjac (f:: JacobianWrapper ) = has_paramjac (f. f)
46024745has_colorvec (f:: JacobianWrapper ) = has_colorvec (f. f)
46034746
4747+ for _fieldname in fieldnames (NonlinearFunction)
4748+ fnname = Symbol (:has_ , _fieldname)
4749+ @eval function $ (fnname)(f:: HomotopyNonlinearFunction )
4750+ $ (fnname)(f. f)
4751+ end
4752+ end
4753+
46044754is_split_function (x) = is_split_function (typeof (x))
46054755is_split_function (:: Type ) = false
46064756function is_split_function (:: Type{T} ) where {T <: Union {
@@ -4692,6 +4842,17 @@ end
46924842
46934843SymbolicIndexingInterface. constant_structure (:: AbstractSciMLFunction ) = true
46944844
4845+ SymbolicIndexingInterface. symbolic_container (fn:: HomotopyNonlinearFunction ) = fn. f
4846+ function SymbolicIndexingInterface. is_observed (fn:: HomotopyNonlinearFunction , sym)
4847+ is_observed (symbolic_container (fn), sym)
4848+ end
4849+ function SymbolicIndexingInterface. observed (fn:: HomotopyNonlinearFunction , sym)
4850+ SymbolicIndexingInterface. observed (symbolic_container (fn), sym)
4851+ end
4852+ function SymbolicIndexingInterface. observed (fn:: HomotopyNonlinearFunction , sym:: Symbol )
4853+ SymbolicIndexingInterface. observed (symbolic_container (fn), sym)
4854+ end
4855+
46954856function Base. getproperty (x:: AbstractSciMLFunction , sym:: Symbol )
46964857 if __has_initialization_data (x) &&
46974858 (sym == :initializeprob || sym == :update_initializeprob! ||
0 commit comments