Skip to content

Commit f9a8622

Browse files
authored
Merge pull request #45 from alexfikl/fix-docs-lines
Fix line numbers in docs
2 parents 47bad08 + c13fd28 commit f9a8622

File tree

6 files changed

+44
-35
lines changed

6 files changed

+44
-35
lines changed

docs/conf.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class GroupHandler_mock:
2828
needs_sphinx = "1.3"
2929

3030
extensions = [
31+
"sphinx.ext.intersphinx",
3132
"sphinx.ext.autodoc",
3233
"sphinx.ext.autosummary",
3334
"sphinx.ext.mathjax",
@@ -61,6 +62,12 @@ class GroupHandler_mock:
6162

6263
toc_object_entries_show_parents = "hide"
6364

65+
intersphinx_mapping = {
66+
"numpy": ("https://numpy.org/doc/stable", None),
67+
"python": ("https://docs.python.org/3", None),
68+
"scipy": ("https://docs.scipy.org/doc/scipy", None),
69+
}
70+
6471
def on_missing_reference(app, env, node, contnode):
6572
if node["reftype"] == "any":
6673
return contnode

docs/index.rst

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The JiTCODE module
77
Overview
88
--------
99

10-
JiTCODE (just-in-time compilation for ordinary differential equations) is an extension of SciPy’s `ODE`_ (`scipy.integrate.ode`) or `Solve IVP`_ (`scipy.integrate.solve_ivp`).
10+
JiTCODE (just-in-time compilation for ordinary differential equations) is an extension of SciPy’s `ODE`_ (:class:`scipy.integrate.ode`) or `Solve IVP`_ (:func:`scipy.integrate.solve_ivp`).
1111
Where the latter take a Python function as an argument, JiTCODE takes an iterable (or generator function or dictionary) of symbolic expressions, which it translates to C code, compiles on the fly, and uses as the function to feed into SciPy’s ODE or Solve IVP.
1212
Symbolic expressions are mostly handled by `SymEngine`_, `SymPy`_’s compiled-backend-to-be (see `SymPy vs. SymEngine`_ for details).
1313

@@ -40,7 +40,7 @@ As with SciPy’s ODE, this documentation assumes that the differential equation
4040

4141
.. math::
4242
43-
\dot{y} = f(t,y)
43+
\dot{y} = f(t,y).
4444
4545
4646
.. _example:
@@ -69,9 +69,11 @@ An explicit example
6969
Details of the building process
7070
-------------------------------
7171

72+
.. currentmodule:: jitcode
73+
7274
To generate the functions needed by SciPy’s ODE or Solve IVP, JiTCODE executes a series of distinct processing steps, each of which can be invoked through a command and tweaked as needed.
7375
These commands execute previous steps as needed, i.e., if they have not been performed yet.
74-
If you are happy with the default options, however, you do not need to bother with this and can just use the commands at the very end of the chain, namely `set_integrator`, `set_initial_value`, or `save_compiled`.
76+
If you are happy with the default options, however, you do not need to bother with this and can just use the commands at the very end of the chain, namely :meth:`~_jitcode.jitcode.set_integrator`, :meth:`~_jitcode.jitcode.set_initial_value`, or :meth:`~_jitcode.jitcode.save_compiled`.
7577

7678
The following diagram details which command calls which other command when needed:
7779

@@ -102,19 +104,19 @@ A more complicated example
102104
Calculating Lyapunov exponents with `jitcode_lyap`
103105
--------------------------------------------------
104106

105-
`jitcode_lyap` is a simple extension of `jitcode` that almost automatically handles calculating Lyapunov exponents by evolving tangent vectors [BGGS80]_.
106-
It works just like `jitcode`, except that it generates and integrates additional differential equations for the tangent vectors.
107-
After every call of `integrate`, the tangent vectors are orthonormalised, and the “local” Lyapunov exponents for this integration step are returned alongside with the system’s state.
107+
:class:`~_jitcode.jitcode_lyap` is a simple extension of :class:`~_jitcode.jitcode` that almost automatically handles calculating Lyapunov exponents by evolving tangent vectors [BGGS80]_.
108+
It works just like :class:`~_jitcode.jitcode`, except that it generates and integrates additional differential equations for the tangent vectors.
109+
After every call of :meth:`~_jitcode.jitcode_lyap.integrate`, the tangent vectors are orthonormalised, and the “local” Lyapunov exponents for this integration step are returned alongside with the system’s state.
108110
These can then be further processed to obtain the Lyapunov exponents.
109111
The tangent vectors are initialised with random vectors, and you have to take care of the preiterations that the tangent vectors require to align themselves.
110-
You also have to take care not to `integrate` for too long to avoid a numerical overflow in the tangent vectors.
112+
You also have to take care not to :meth:`~_jitcode.jitcode_lyap.integrate` for too long to avoid a numerical overflow in the tangent vectors.
111113

112114
Estimates for the Lyapunov vectors are returned as well.
113115

114116
.. automodule:: double_fhn_lyapunov
115117

116118
.. literalinclude:: ../examples/double_fhn_lyapunov.py
117-
:emphasize-lines: 20-21,26,28-36
119+
:emphasize-lines: 22-23,27,29-37
118120
:start-after: example-start
119121
:dedent: 1
120122
:linenos:
@@ -124,7 +126,7 @@ Estimates for the Lyapunov vectors are returned as well.
124126
Calculating transversal Lyapunov exponents with `jitcode_transversal_lyap`
125127
--------------------------------------------------------------------------
126128

127-
`jitcode_transversal_lyap` is a variant of `jitcode_lyap` that calculates Lyapunov exponents transversal to a user-defined synchronisation manifold.
129+
:class:`~_jitcode.jitcode_transversal_lyap` is a variant of :class:`~_jitcode.jitcode_lyap` that calculates Lyapunov exponents transversal to a user-defined synchronisation manifold.
128130
It automatically conflates the differential equations of a group of synchronised components into one equation on the synchronisation manifold.
129131
Moreover, it transforms the equations for the tangent vectors such that the tangent vector is automatically orthogonal to the synchronisation manifold.
130132
If you are interested in the mathematical details, please read `the accompanying paper`_.

examples/SW_of_Roesslers.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,25 @@
1212
\\dot{z}_i &= b + z_i (x_i -c) + k \\sum_{j=0}^N (z_j-z_i)
1313
\\end{alignedat}
1414
15-
The control parameters shall be :math:`a = 0.165`, :math:`b = 0.2`, :math:`c = 10.0`, and :math:`k = 0.01`. The (frequency) parameter :math:`ω_i` shall be picked randomly from the uniform distribution on :math:`[0.8,1.0]` for each :math:`i`. :math:`A∈ℝ^{N×N}` shall be the adjacency matrix of a one-dimensional small-world network (which shall be provided by a function `small_world_network` in the following example code). So, the :math:`x` components are coupled diffusively with a small-world coupling topology, while the :math:`z` components are coupled diffusively to their mean field, with the coupling term being modulated with :math:`\\sin(t)`.
15+
The control parameters shall be :math:`a = 0.165`, :math:`b = 0.2`, :math:`c = 10.0`, and :math:`k = 0.01`. The (frequency) parameter :math:`ω_i` shall be picked randomly from the uniform distribution on :math:`[0.8,1.0]` for each :math:`i`. :math:`A∈ℝ^{N×N}` shall be the adjacency matrix of a one-dimensional small-world network (which shall be provided by a function :any:`small_world_network` in the following example code). So, the :math:`x` components are coupled diffusively with a small-world coupling topology, while the :math:`z` components are coupled diffusively to their mean field, with the coupling term being modulated with :math:`\\sin(t)`.
1616
1717
Without further ado, here is the example code (`complete running example <https://raw.githubusercontent.com/neurophysik/jitcode/master/examples/SW_of_Roesslers.py>`_); highlighted lines will be commented upon below:
1818
1919
.. literalinclude:: ../examples/SW_of_Roesslers.py
2020
:linenos:
2121
:dedent: 1
2222
:lines: 63-
23-
:emphasize-lines: 9, 25-26, 34, 31, 43
23+
:emphasize-lines: 10, 26-27, 35, 32, 44
2424
2525
Explanation of selected features and choices:
2626
27-
* The values of :math:`ω` are initialised globally (line 9). We cannot just define a function here, because the parameter is used twice for each oscillator. Moreover, if we were trying to calculate Lyapunov exponents or the Jacobian, the generator function would be called multiple times, and thus the value of the parameter would not be consistent (which would be desastrous).
27+
* The values of :math:`ω` are initialised globally (line 10). We cannot just define a function here, because the parameter is used twice for each oscillator. Moreover, if we were trying to calculate Lyapunov exponents or the Jacobian, the generator function would be called multiple times, and thus the value of the parameter would not be consistent (which would be desastrous).
2828
29-
* Since we need :math:`\\sum_{j=0}^N x_j` to calculate the derivative of :math:`z` for every oscillator, it is prudent to only calculate this once. Therefore we define a helper symbol for this in lines 25 and 26, which we employ in line 34. (See the arguments of `jitcode` for details.)
29+
* Since we need :math:`\\sum_{j=0}^N x_j` to calculate the derivative of :math:`z` for every oscillator, it is prudent to only calculate this once. Therefore we define a helper symbol for this in lines 26 and 27, which we employ in line 35. (See the arguments of `jitcode` for details.)
3030
31-
* In line 31, we implement :math:`\\sin(t)`. For this purpose we had to import `t` in line 1. Also, we need to use `symengine.sin` – in contrast to `math.sin` or `numpy.sin`.
31+
* In line 32, we implement :math:`\\sin(t)`. For this purpose we had to import `t` in line 3. Also, we need to use `symengine.sin` – in contrast to :func:`math.sin` or :data:`numpy.sin`.
3232
33-
* As this is a large system, we use a generator function instead of a list to define :math:`f` (lines 28-35) and have the code automatically be split into chunks of 150 lines, corresponding to the equations of fifty oscillators, in line 43. (For this system, any reasonably sized multiple of 3 is a good choice for `chunk_size`; for other systems, the precise choice of the value may be more relevant.) See `large_systems` for the rationale.
33+
* As this is a large system, we use a generator function instead of a list to define :math:`f` (lines 29-36) and have the code automatically be split into chunks of 150 lines, corresponding to the equations of fifty oscillators, in line 44. (For this system, any reasonably sized multiple of 3 is a good choice for `chunk_size`; for other systems, the precise choice of the value may be more relevant.) See `large_systems` for the rationale.
3434
"""
3535

3636
if __name__ == "__main__":

examples/double_fhn_example.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
66
.. math::
77
8-
f(y) = \\left(
9-
\\begin{matrix}
10-
y_0 ( a-y_0 ) ( y_0-1) - y_1 + k (y_2 - y_0) \\\\
11-
b_1 y_0 - c y_1 \\\\
12-
y_2 ( a-y_2 ) ( y_2-1 ) - y_3 + k (y_0 - y_2)\\\\
8+
f(y) =
9+
\begin{bmatrix}
10+
y_0 ( a-y_0 ) ( y_0-1) - y_1 + k (y_2 - y_0) \\
11+
b_1 y_0 - c y_1 \\
12+
y_2 ( a-y_2 ) ( y_2-1 ) - y_3 + k (y_0 - y_2)\\
1313
b_2 y_2 - c y_3
14-
\\end{matrix} \\right),
14+
\end{bmatrix},
1515
1616
and :math:`a = -0.025794`, :math:`b_1 = 0.0065`, :math:`b_2 = 0.0135`, :math:`c = 0.02`, and :math:`k = 0.128`.
1717
Then the following code integrates the above for 100000 time units (after discarding 2000 time units of transients), with :math:`y(t=0) = (1,2,3,4)`, and writes the results to :code:`timeseries.dat`:

examples/double_fhn_transversal_lyap.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
For instance, let’s interpret the system from `example` as two oscillators (which is what it is), one consisting of the first and second and one of the third and fourth component. Furthermore, let’s change the control parameters a bit to make the two oscillators identical. We can then calculate the transversal Lyapunov exponents to the synchronisation manifold as follows (important changes are highlighted):
55
66
.. literalinclude:: ../examples/double_fhn_transversal_lyap.py
7-
:emphasize-lines: 6, 12, 14, 17, 19-20
7+
:emphasize-lines: 7, 13, 15, 18, 20-22
88
:start-after: example-st\u0061rt
99
:dedent: 1
1010
:linenos:
1111
12-
Note that the initial state (line 17) is reduced in dimensionality and there is only one component for each synchronisation group.
12+
Note that the initial state (line 18) is reduced in dimensionality and there is only one component for each synchronisation group.
1313
"""
1414

1515
if __name__ == "__main__":

examples/lotka_volterra.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,21 @@
1616
1717
.. literalinclude:: ../examples/lotka_volterra.py
1818
:start-after: example-st\u0061rt
19-
:lines: 1-2
19+
:lines: 1-3
2020
:dedent: 1
2121
2222
… and defining the control parameters:
2323
2424
.. literalinclude:: ../examples/lotka_volterra.py
2525
:start-after: example-st\u0061rt
26-
:lines: 4-7
26+
:lines: 5-8
2727
:dedent: 1
2828
2929
The `y` that we imported from `jitcode` has to be used for the dynamical variables. However, to make our code use the same notation as the above equation, we can rename them:
3030
3131
.. literalinclude:: ../examples/lotka_volterra.py
3232
:start-after: example-st\u0061rt
33-
:lines: 9
33+
:lines: 10
3434
:dedent: 1
3535
3636
We here might as well have written `R,B = y(0),y(1)`, but the above is more handy for larger systems. Note that the following code is written such that the order of our dynamical variables does not matter.
@@ -39,7 +39,7 @@
3939
4040
.. literalinclude:: ../examples/lotka_volterra.py
4141
:start-after: example-st\u0061rt
42-
:lines: 11-14
42+
:lines: 12-15
4343
:dedent: 1
4444
4545
Note that there are other ways to define the derivative, e.g., used in the previous and following example.
@@ -48,35 +48,35 @@
4848
4949
.. literalinclude:: ../examples/lotka_volterra.py
5050
:start-after: example-st\u0061rt
51-
:lines: 16
51+
:lines: 17
5252
:dedent: 1
5353
5454
Before we start integrating, we have to choose an integrator and define initial conditions. We here choose the 5th-order Dormand–Prince method. Moreover the initial :math:`B` shall be 0.5, the initial :math:`R` shall be 0.2, and the starting time should be :math:`t=0`.
5555
5656
.. literalinclude:: ../examples/lotka_volterra.py
5757
:start-after: example-st\u0061rt
58-
:lines: 17-19
58+
:lines: 18-20
5959
:dedent: 1
6060
6161
We then define an array of time points where we want to observe the system, and a dictionary of empty lists that shall be filled with our results.
6262
6363
.. literalinclude:: ../examples/lotka_volterra.py
6464
:start-after: example-st\u0061rt
65-
:lines: 21-22
65+
:lines: 22-23
6666
:dedent: 1
6767
6868
Finally, we perform the actual integration by calling `ODE.integrate` for each of our `times`. After this, we use `ODE.y_dict` to access the current state as a dictionary and appending its values to the respective lists.
6969
7070
.. literalinclude:: ../examples/lotka_volterra.py
7171
:start-after: example-st\u0061rt
72-
:lines: 23-26
72+
:lines: 24-27
7373
:dedent: 1
7474
7575
We can now plot or analyse our data, but that’s beyond the scope of JiTCODE. So we just save it:
7676
7777
.. literalinclude:: ../examples/lotka_volterra.py
7878
:start-after: example-st\u0061rt
79-
:lines: 28
79+
:lines: 29
8080
:dedent: 1
8181
8282
Taking everything together, our code is:
@@ -101,9 +101,9 @@
101101
R,B = dynvars = [ y(i) for i in range(2) ]
102102

103103
lotka_volterra_diff = {
104-
B: γ*B - φ*R*B,
105-
R: -ω*R + ν*R*B,
106-
}
104+
B: γ*B - φ*R*B,
105+
R: -ω*R + ν*R*B,
106+
}
107107

108108
ODE = jitcode(lotka_volterra_diff)
109109
ODE.set_integrator("dopri5")

0 commit comments

Comments
 (0)