|
| 1 | +# Finding Steady States through Homotopy Continuation |
| 2 | + |
| 3 | +The steady states of a dynamical system ${dx \over dt} = f(x)$ can be found by solving $0 = f(x)$. This is typically a hard problem, and generally, there is no method that guarantees to find all steady states for a system that has multiple ones. However, most CRNs generate polynomial systems (the main exception is when Hill functions with non-integer exponents are used). The roots of these can reliably be found through a *homotopy continuation* algorithm. This is implemented in Julia through the [HomotopyContinuation.jl](https://www.juliahomotopycontinuation.org/) package. In this tutorial, we will demonstrate how homotopy continuation can be used to find the steady states of a CNR implemented in Catalyst. |
| 4 | + |
| 5 | +## Basic Example |
| 6 | +For this tutorial, we will use a model from the Wilhem (2009) paper (which demonstrates bistability in a small CRN). We declare the model and the parameter set for which we want to find the steady states: |
| 7 | +```@example hc1 |
| 8 | +using Catalyst |
| 9 | +wilhelm_2009_model = @reaction_network begin |
| 10 | + k1, Y --> 2X |
| 11 | + k2, 2X --> X + Y |
| 12 | + k3, X + Y --> Y |
| 13 | + k4, X --> 0 |
| 14 | +end k1 k2 k3 k4 |
| 15 | +p = [:k1 => 8.0, :k2 => 2.0, :k3 => 1.0, :k4 => 1.5] |
| 16 | +``` |
| 17 | +Next, we will need to extract the actual equations from our model. In addition, we will substitute in our parameter values. |
| 18 | +```@example hc1 |
| 19 | +ns = convert(NonlinearSystem,wilhelm_2009_model) |
| 20 | +subs = Dict(Pair.(ModelingToolkit.parameters(ns),last.(p))) |
| 21 | +new_eqs = map(eq -> substitute(eq.rhs,subs), equations(ns)) |
| 22 | +``` |
| 23 | +Finally, we use the `as_polynomial` function to read our symbolic expression as a polynomial, within it, we can apply homotopy continuation's `solve` command to find the roots. In addition, we use the `real_solutions` to filter away imaginary roots (as CRNs' states typically are non-imaginary): |
| 24 | +```@example hc1 |
| 25 | +using HomotopyContinuation |
| 26 | +sols = real_solutions(as_polynomial((f, x...) -> HomotopyContinuation.solve(collect(x)), new_eqs...)) |
| 27 | +``` |
| 28 | +While it is not the case for this CRN, we note that some solutions with negative species concentrations may still appear. Typically, these will need to be filtered away as well. |
| 29 | + |
| 30 | +## Rational Polynomial Systems |
| 31 | +It is not uncommon for CRNs to generate systems corresponding to rational multivariate polynomials (e.g. through Hill functions). The roots of these can also be found using homotopy continuation. An expanded tutorial for this will be published once some awaited improvements to the `as_polynomial` function are completed. |
| 32 | + |
| 33 | +## Systems with Conservation Laws |
| 34 | +Finally, some systems are underdetermined, and have an infinite number of possible steady states. These are typically systems containing a conservation law, e.g. |
| 35 | +```@example hc3 |
| 36 | +using Catalyst |
| 37 | +two_state_model = @reaction_network begin |
| 38 | + (k1,k2), X1 <--> X2 |
| 39 | +end k1 k2 |
| 40 | +``` |
| 41 | +However, the conservation laws can be computed using the `conservationlaws` function. By supplying these, as well as fixed concentrations (in this case the total amount of *X*, that is *X1+X2*), steady states can be found. First, we set the default values of the system's initial conditions and steady states. This will allow the system to automatically find the conserved amounts. |
| 42 | +```@example hc3 |
| 43 | +setdefaults!(two_state_model, [:X1 => 1.0, :X2 => 1.0, :k1 => 2.0, :k2 => 1.0]) |
| 44 | +``` |
| 45 | +Next, we create a `NonlinearSystem`, while also removing the redundant equation. |
| 46 | +```@example hc3 |
| 47 | +ns = convert(NonlinearSystem,two_state_model; remove_conserved=true) |
| 48 | +``` |
| 49 | +Again, we will create the dictionary for parameter values that we will sub in. However, we will do it slightly differently so that the conserved quantitites are accoutned for. |
| 50 | +```@example hc3 |
| 51 | +const MT = ModelingToolkit |
| 52 | +subs = Dict(MT.parameters(ns) .=> MT.varmap_to_vars([], MT.parameters(ns); defaults=MT.defaults(ns))) |
| 53 | +``` |
| 54 | +We now extract the equation produced by the conservation law, and then sub in the parameter values creating a final set of equations (like previously). Unlike previously, we have to do `eq.rhs-eq.lhs`, as `cons_eq` may contain important information on both the lhs and rhs. |
| 55 | +```@example hc3 |
| 56 | +cons_eq = conservedequations(two_state_model) |
| 57 | +new_eqs = map(eq -> substitute(eq.rhs-eq.lhs,subs), [equations(ns)...;cons_eq...]) |
| 58 | +``` |
| 59 | +Finally, we compute the solution: |
| 60 | +```@example hc3 |
| 61 | +using HomotopyContinuation |
| 62 | +sols = real_solutions(as_polynomial((f, x...) -> HomotopyContinuation.solve(collect(x)), new_eqs...)) |
| 63 | +``` |
0 commit comments