Model(unknown_inputs=)declares unknown functions of time: symbols in the right-hand sides and observables without an equation. A direction may change them along with the parameters, whilerankanddimcount the parameters and initial values only. An exact direction lists the change of each input ininput_change, printed under "input change:".- The inputs enter as chains of jets whose initial values are nuisance coordinates of the
kernel.
info["unknown_inputs"]lists the jets, the Lie order up to which they are exact and the rank of the jet columns;reconst_control(input_jet_order=)sets their number. A rank that is neither full nor matched by exact directions is a lower bound. - A string in
conditionsrenames an unknown input per condition. Across an event the input stays analytic, so a jump of a state can separate parameters that the input would otherwise absorb. Underequilibratean unknown or known input is zero at rest and takes its jets from the start on. Switches, an event or atrafoentry for an unknown input andengine="symbolic"are refused.
Model(known_inputs=)declares known functions of time of no assumed form: jet chains whose initial values are known symbols.Symmetries.solution_count()counts the values of the coordinates with the output of a random point modulo a prime (msolve), over the algebraic closure; more than one is a candidate discrete symmetry. It reads the clock and known inputs, substitutes thetrafointo the initial values as the detection does, takes a one-row grid and one-element lists, returns None for a model that is not rational and refuses switches and a result underequilibrateorreduce_cq.
- A closed form reads every name of the model as a symbol, also
E,I,S,N,rforbeta. A kernel check that evaluates only part of the entries stays"checked". - An event value after the start reads the states just before the event; one at the start reads the initial values before the events. A state without dynamics that an event sets to another state is analyzed as a state.
- When the saturation guard sees the rank grow past the Lie order used, the saturation is repeated from past that order.
- A free exponent of a number enters through the primes of the number; exponent terms that are rational combinations of each other up to a constant share their leaves, and a logarithm inside an exponent is a leaf of its own.
- A symbol in two different logarithms, or with a free power beside an affine logarithm, gets no logarithmic coordinate; auxiliary states take its powers and logarithms.
positiveaccepts expressions such as"1-x".- Condition columns and constant states keep their logarithms and free powers, which become
numbers per condition;
0^nis 0 for a positive exponentn. - A free power of a state with a given initial value starts at the power of that value.
- The reset of a root event enters the stacked rows of a model with switches. When the rule of the switches leaves directions open without candidates, the report says so.
- A switch that the default
positive=Truedecides through the sign of a state warns. regimesnames a switching surface in any algebraic form.info["timing"]holds the seconds at each stage of the analysis.timein an initial value reads the clock at the start, in an event value at the time of the event. The model has the clock wherever a right-hand side, observable,trafovalue or condition cell readstime; underequilibratethe clock is an input that rests at zero and counts from the start, andexp()of it is refused by name.- A
trafovalue or condition cell enters the equations as one operand, in parentheses. - An event time that a condition cell or a per-condition
trafosets is resolved per condition, also to the start. scalings_onlyholds the initial values, event values and times, per-conditiontrafoentries, one-row grids and known inputs as the full detection does and reports its coordinates; event times in parameters are supported.gaugekeeps the unknown inputs.reduce_cqreads thetotalsof an ODE model; a total that the right-hand sides do not conserve is an error. A moiety species with an initial value intrafostays a state where another species of the moiety can be eliminated.- A right-hand side that the
trafosets to zero rests like a constant state. - A name in
known_inputs,inputs,fixed,parameters, a condition column or an eventvarthat the model does not hold is an error; inputs and event variables are states. A name inpositiveoutside the model warns. - An input starts at zero: an initial value of an input in
trafoor a condition column is an error that names the event to set it with.Model(inputs=)documents it. - A
trafoentry that replaces a symbol a condition column sets warns. detect()keeps a copy of the model, so later changes of the model leave the result as it is.- Under
equilibrate,info["bound"]says that the error bound does not cover a start at rest. - A Lie derivative past the size cap leaves the gap order a lower bound; an exponential at the start takes a generic value in the gap bound.
- The scaling rows expand each rational right-hand side once, in sparse polynomial arithmetic.
- A state with a signed net rate such as
-k*(x - u)rests at zero, on the reaction and the ODE path and per condition; a state whose right-hand side vanishes at rest keeps its resting value as a coordinate. - Exponentials of parameters outside the resting model are supported.
- A joint solve that fails names the condition.
- A full-rank result lists the parameter coordinates only.
reduce()refuses a direction of level"checked"and a result whose saturation check failed, unlessallow_checked=True.- The closed loop applies the trafo to symbolic condition cells. It fails when a trafo
entry has no effect, and is reported as not run when the detection refuses the reduced
model; the summary line says when it does not confirm the reduction. An entry for a
symbol of the grid goes into its cells, an entry that the model trafo consumes stays
out of the composed trafo, and under
equilibratea numeric pin of a resting value goes intofixed(Reduction.trafodocuments it). - Section candidates start with pins of one coordinate; balances through fixed symbols follow those between coordinates and displace none of them. The reason a block is not reduced is printed.
- A declared positive expression such as
"1-a"bounds the domain of the reduction: a section that leaves the bound counts as partial, and pins in the middle of a bound are tried first. Symmetries.reduce()returns a copy of the reduction computed first for the same arguments.reduce()andreduce_json()take the declared positive coordinates from the detection without a warning for the states and fixed names among them.- A refused
"checked"direction names why it is checked: without an error bound, or on part of its entries.
- The reader drops species without dynamics, events or inputs that start at one value, and sets a total that cancels below rounding to zero. The initial values of inputs under preequilibration raise no warning.
read_petab()andModel.from_petab()read a PEtab problem, format version 1 or 2, into aModel(extrasymident[petab]). Volumes that change in time dilute the concentrations, and a reset volume keeps the amounts of its species.
Model(equilibrate=, positive=, reduce_cq=)set the defaults ofdetect()for the model;read_petab()sets them from the problem.reduce(positive=)defaults to the setting of the detection.- A condition starts at t = 0, or at its earliest event when that comes before.
- New level
"checked": a closed form checked at random points without an error bound. A"verified"direction always has its probability ininfo["bound"], and a rank without a probability is a lower bound. A closed form whose kernel check can evaluate only part of its entries is"checked"as well.Symmetries.unproven()returns the verified and checked directions. - Directions of a model with switches that the rule of the switches does not prove are no
longer reported as symmetries: they are listed under
info["switching"]["candidates"], and the printout says how many more directions there may be. - New
info["assumptions"]andReduction.assumptions: the declareddomainand the sides of switches thatregimesdeclares at the start (starts), together with theerror_boundof the verification. - The start sides that
regimesdeclares move frominfo["switching"]["conditions"][i]["assumptions"]to["declared"].
- More section claims are proven: that every orbit meets a section at most once, for any
number of generators (
blocks[i]["injective"]), and that every level set of the invariants is one orbit, so that every orbit meets the section (blocks[i]["reach"]), also under partial coverage. - A section on a face of the parameter space is proven to give the output of every orbit
in the limit, also under
equilibrate. A face whose resting state is only checked at random points hasblocks[i]["face_level"]"checked", and so has its block. - A section claim that is not proven is named under
blocks[i]["unproven"], makes the block"open"and gives a warning. This replaces the level"assumed"andblocks[i]["assumptions"];reduce(verbose=)is removed. blocks[i]["new_parameters"],blocks[i]["solved_domain"]andchoicesinblocks[i]andfamily[i]replacesurvivor_meaning,carrier_domainandadmissible.- The section search also tries a product of two coordinates at one. A search that a
budget cuts short is named in
limits. zero_limitsreports "no" only when every branch of the face equations is solved.- Ranks and signs in the reduction are exact; no floating point remains.
equilibrate: conditions at rest that share parameters are continued as power series from a common start instead of being solved jointly with msolve;SYMIDENT_NODIAGswitches this off.info["series_certified"]says whether the series order is proven sufficient; otherwise the rank is a lower bound. msolve uses the cores of the call.- Condition-specific parameters in log coordinates map back to their names.
switches()also setsCACHE,MSOLVEand the switches of the msolve build;install_msolve()takesMSOLVE_VERSIONandJOBSas its defaults.LIBS_CACHEis removed,SYMIDENT_CACHEsets the cache.ROUTEDIAGreplacesROBUSTDIAG, andBLOCKMBis listed.
- On Windows the msolve builds in the cache are found as
msolve.exe.
- Every direction has a
level:"exact"(proven over Q),"verified"(checked at random points modulo a large prime) or"open"(no closed form).Symmetry.certifiedis gone;Symmetries.unproven()returns the verified directions. - Closed forms are proven over Q through a lifting field, also per regime, in the recast
coordinates of symbolic exponents, for polynomial outputs in t and on resting states.
reconst_control(exact_proof=, exact_work_cap=)controls the proof of combined regimes.Symmetry.state_componentsholds the state components of an exact direction. info["rank_status"]says whether the rank is proven, verified or a lower bound, and why. A rank from the invariant fields is verified (info["rank_fields"]), checked at random points modulo the drawn verification prime;info["rank_fields_bound"]bounds the probability that a wrong field passes.info["bound"]is the probability that a wrong closed form passes the kernel check, also through events after the start; it is given only where the Lie and gap orders are proven.- Under events after the start, the gap order is raised to a proven rank bound
(
info["gap_certified"],info["gap_certificate"]); otherwise the rank is a lower bound with an entry ininfo["limits"]. engine="symbolic"proves its Lie order, its closed forms and its rank (info["lie_certificate"]).info["proof"]says per closed direction why the exact proof does not apply.- Models with switches list the directions the rule does not prove as
"verified"(info["switching"]["uncertified"]).
- The homotopy route runs without
equilibrate, through events after the start, with radicals in initial values and in recast coordinates (reconst_control(homotopy_degree=)). - Entries past
degree_capare probed up toreconst_control(degree_cap_max=). Directions of minimal support are found at any width. - Under
equilibratewith reactions, only drained species rest at zero and a rate is zero at rest only when it vanishes exactly. A held moiety pivot rests at its parameter. The weights that find drained species solve their linear program exactly over Q. - Results do not depend on
coresorPYTHONHASHSEED;reconst_control(seed=)seeds every random choice. Work budgets replace clocks (SYMIDENT_JETWORK,work_cap). info["attempts"],info["errors"],info["limits"],info["branches"]andinfo["settings"]record routes tried, exceptions, budgets reached, resting state branches and settings;summary()shows them.SYMIDENT_DEBUGraises the exceptions.symident.switches()sets switches for awithblock;SYMIDENT_DIAGturns on all diagnostics. Unused route switches are removed; an unknownSYMIDENT_*name warns.
- The expression functions of cppDE parse:
exp2,cbrt,root,pow, the inverse reciprocal trigonometric and hyperbolic functions andatanh.floor(),ceiling()andround()are refused;erf()anderfc()needengine="symbolic". piis the number and cannot name a symbol.==and!=decide by identity. Names such asN,S,E,Iorbetastay model symbols. A switch on parameters alone needs its side inregimes.- The printout reads
X = Σᵢ ξ(i) ∂ᵢ; the docs write θ for the parameters and ξ for the components of a generator.
reduce()reads the levels: an"open"direction is an error unlessallow_open=True, a"verified"one warns. The reduction has a level per block and overall ("exact","verified","assumed"with the named assumptions).reduce()checks its trafo over Q (Reduction.checks) and reruns the detection on the transformed model (check=True).Reduction.errorslists failing sections.- Signs, invariant independence and ranks are decided exactly or with guaranteed precision;
floats only order candidates. A scaling pinned at a coordinate not declared positive
covers part of the orbits (
coverage = "partial"). - The section search stops after
reduce(work_cap=4000)candidates;timeoutdefaults to infinity. Reached limits are listed inReduction.limits.
install_msolve()builds GMP and FLINT for the generic architecture instead of the CPU it runs on. The binary no longer stops with an illegal instruction on another CPU sharing the cache, or on a virtual machine that hides instruction sets its CPU model implies.- The reduction report lists each section as its equation.
summary(detailed=True)explains each section. - The summary no longer shows how a closed form was found.
- The block lines of
summary()are aligned in columns and show the section as its equation, with the number of possible choices.
log(x, b)andatan2(y, x)parse: the commas between the arguments were dropped.atanh()of an argument whose logarithms cancel in part, such asatanh(x/(1 + x)), no longer stops with aKeyError.
- Wheels for Python 3.14.
- Linux wheels are built on manylinux_2_28 and need glibc 2.28 or newer; on the older manylinux2014 base, installing the wheel built SciPy from source.
- The tests pass on Windows: they read their data as UTF-8, and the msolve tests that run a shell script are skipped there.
First release.
Model,detect()andreduce(): non-identifiable directions of ODE models with observables, conditions, events and inputs, as exact generators where they close, and the reparametrization that removes them.- Observability rank over finite fields in a C++ kernel, with a certified Lie order, exact scaling symmetries and rank proofs by scalings or invariant fields.
- Elementary functions of states (logarithms, inverse trigonometric and hyperbolic functions, powers of sums, nested) recast into rational form; their transcendental initial values become generic leaves.
- Steady-state constraints (
equilibrate) through the joint resting-state system. Directions that no sampling route closes are fitted along parameter lines through the continued resting state, in the parameters and, where needed, the resting states (reconst_control(homotopy=)). - Switches in right-hand sides and observables:
piecewise()in SBML order,ifelse(), comparisons,&&,||,!,Heaviside(),sign(),abs(),max()andmin(), and events with aroot. A direction is reported when the observables of every regime that the declared signs do not exclude stay unchanged along it, it maps every surface of a visible switch to itself and keeps the events; a switch hidden from the observables may move.Model(regimes=)restricts the analysis to the regimes an experiment visits. The rank is certified between the stacked rows of the regimes and directions proven symbolically, and an error is raised where they do not meet. - Reduction by scaling transversals, module reduction and invariants (monomial, polynomial, rational, Darboux, exponential), with positivity certificates and face sections.
reduce()returns the best reparametrization and lists the others underalternatives(reduce(alternatives=True)); dependent directions are named underdependent.install_msolve()builds msolve, used for coupled steady states, into a per-user cache.symident.rjson: JSON interface for host languages.