CyRK - Change Log¶
2026¶
v0.20.X¶
v0.20.0 (2026-10-10)¶
New Features¶
Tsit5: the 5(4) pair of Tsitouras (2011). It costs the same six diffeq calls per step as RK45 and on the benchmark problems needed 7% to 49% fewer calls than RK45 to reach errors of 1e-6 and below (it is not always cheaper: on a Kepler orbit with eccentricity 0.9 it needed 3% to 6% more). Its fourth-order interpolant is built from the step’s own stages, so dense output,
t_eval, and events cost no extra calls.Vern7 and Vern8: Verner’s (2010) “most efficient” 7(6) and 8(7) pairs, at 10 and 13 diffeq calls per step. Vern8 needed 7% to 29% fewer calls than DOP853 for relative errors of 1e-6 to 1e-10 on the benchmark problems. Vern7 needed up to about 40% more than DOP853 on most of them and up to 19% fewer on the Pleiades problem. Their interpolants match the order of the method (7 and 8) and need 5 and 7 extra stages, which are only evaluated on steps that build an interpolant.
Vern7 uses the interpolant coefficients as Verner corrected them in 2024.
Vern8’s error stops improving near a relative error of 1e-12 on long integrations, where rounding in its large weights accumulates. DOP853 and Vern7 keep improving to
rtol=1e-13.
All three are available from
cysolve_ivp(ODEMethod.TSIT5,ODEMethod.VERN7,ODEMethod.VERN8, appended to the enum as 9, 10, and 11),pysolve_ivp, andnbsolve2_ivp(method="Tsit5","Vern7", or"Vern8"), and support everything the other explicit methods do. The legacynbsolve_ivpdoes not provide them.The tableaus, error weights, extra stages, and interpolants were checked against the Runge-Kutta order conditions in high-precision arithmetic (every condition holds to better than 1e-33 for the source coefficients, and to about 3e-32 for the values written to “rk.cpp” with about 36 significant digits). The Tsit5 tableau comes from OrdinaryDiffEq.jl (MIT license, noted in “LICENSE.md”) and its interpolant weights were derived from it. The Verner coefficients are from Verner’s published files.
The interpolants are stored as their values at Chebyshev-Lobatto nodes and evaluated with the barycentric formula (“dense.cpp”). Evaluated from its monomial coefficients, which reach 3e5, Vern8’s interpolant would lose about two digits at tight tolerances (7e-11 instead of 1e-11 on a Kepler orbit at
rtol=1e-13). With the barycentric form the dense output is as accurate as the steps.
Updates and fixes GitHub actions.
Performance¶
“Performance/performance.py” now tracks Tsit5, Vern7, and Vern8 (“cyrk_performance-Tsit5.csv”, “-Vern7.csv”, and “-Vern8.csv”).
Fixes¶
Dense output of a backward integration used the interpolant of the neighboring step (“cysolution.cpp”,
CySolverResult::call). Between the step times its values were wrong at the level of the step size (errors from 1e-8 to 3e-5 where forward dense output gave 1e-10), and at t_start and anywhere in the first step it used the placeholder interpolant, returning NaN (0 for LSODA). Every method was affected. Each time is now evaluated with the interpolant of the step that contains it, and backward dense output is as accurate as forward.pysolve_ivp: an event withterminal = Falseorterminal = 0ended the integration at its first occurrence, because the value was used as a count of allowed occurrences. As in SciPy and the “Events” documentation, False and 0 now mean a non-terminal event (max_allowedstill applies), True and a positive int n end the integration at the n-th occurrence, and a negative value raises aValueError.LSODA failed with “Required step size is less than spacing between numbers” at the first step no larger than the spacing between numbers at t, a check added in v0.19.2. ODEPACK (and SciPy’s LSODA) take such steps and continue, and they can be temporary: far from t = 0 repeated error test failures can cut the step to the spacing before it grows back, and after a switch to the Adams formulas a stale Lipschitz estimate from the BDF steps can hold the step at the spacing until the next stiffness test, 20 steps later. LSODA now fails only after more than
LSODA_MAX_TINY_STEPS(100, “lsoda.hpp”) such steps in a row, which still ends the creep that non-finite rates cause. A step that left t unchanged counts as one too: ODEPACK tests the step size before its error test cuts it further, so its own count misses some of them.A failed step lost its error status when the problem had events: the event check that followed the step replaced the status with
NO_ERROR. BDF, LSODA, and Radau then ended withsuccess = False, status 0, and the message “No errors were encountered”, and RK23, RK45, and DOP853 stepped on past the failure until the step limit. Events are no longer checked after a failed step, so the step’s own status (“cysolver.cpp”,CySolverBase::take_step) is reported.The dense LU solve behind BDF, LSODA, and Radau (“c_lu.cpp”,
c_dense_lu_solveandc_complex_dense_lu_solve) gave wrong results whenever the factorization pivoted in more than one column. The factorization swaps whole rows, as LAPACK’s dgetf2 does, but the solve applied each interchange during the forward substitution, as LINPACK’s dgesl does for a factorization that leaves the earlier columns of L in place. The solve now applies every interchange first, as LAPACK’s dgetrs does. A problem whose Jacobian has entries far larger than its diagonal (a stiff variable strongly coupled to slow ones) got wrong Newton corrections, so BDF and Radau took many times the steps they needed, or failed with step-size errors, and Radau’s error estimates were wrong.LSODA with
lbandandubandand no analytic Jacobian could fail or slow down when the banded factorization pivoted. The banded LU factorization (“c_lu.cpp”,c_banded_lu_factor) did not clear the fill-in rows of each column it reached, as LAPACK’s dgbtf2 does, and LSODA’s finite-difference Jacobian only rewrites the band, so the previous factorization’s fill-in entered U through the row interchanges. On a stiff lower-bidiagonal chain withlband=1, uband=0, LSODA failed after 310 steps where the dense Jacobian takes 492. It now takes the same 492.The first step size search (“cysolver.cpp”,
CySolverBase::p_calc_first_step_size, used by every method but LSODA) called the differential equation beyond the end of a span shorter than its probe step (at t = 0.014 for a span of 1e-9). The probe now stays inside the span and the first step is capped at the span and atmax_step, as in SciPy’sselect_initial_step. The search also restores the initial state when it is done instead of leaving the solver at the probe point.Radau grew its step by 9 (the safety factor times
MAX_FACTOR) instead of SciPy’s 10 after a step with a zero error estimate, for example when nothing changes. It took 18 steps where SciPy takes 17 to cover 1e10 from a constant state.pysolve_ivpraised anIndexErrorfor anrtoloratolgiven as a numpy scalar (such asnp.float64(1e-6)) and anAttributeErrorfor one given as an int or a list. Any real scalar or array-like is now accepted.BDF called the differential equation once more than it needed to each time it refreshed an analytic Jacobian (
jac_ptr) after a failed Newton iteration. Only the finite-difference estimate needs that derivative.LSODA failed at its first step (“The Newton iteration of an implicit method failed to converge”) on a stiff problem started on its slow manifold, such as a fast variable at its quasi-static value. Its first step size comes from f(t0), which then has no fast component, and the Adams functional iteration cannot converge at it. ODEPACK (and SciPy’s LSODA) cuts the step by 4 after each failure and gives up after 10, a factor of about 3e5 in all, which fell short from a stiffness of about 1e6 up (“c_lsoda.cpp”,
stoda_handle_corrector_failure). The first step now gets 10 more retries, which bound the step by the Lipschitz constant that the failed iteration measured, so a stiffness of up to at least 1e20 now starts. Problems whose first step ODEPACK starts take the same steps as before.LSODA could hold its step at the Adams stability bound without end: 5.3e-7 for a fast variable of stiffness 1e6 at rtol 1e-9, and 7.5e-12 near the singular center of a planet’s structure integration (the gravity equation’s 2/r). There the corrector converges at roundoff, so it forms no new Lipschitz estimate, and the step selection holds h through its order increase branch, which skips ODEPACK’s stability test and so never sets
irflag. The stiffness test then kept the Adams formulas. The hold now setsirflagwhen the step is at the stability bound, and LSODA switches to BDF. ODEPACK and SciPy’s LSODA hold the step in both cases.
Documentation¶
“Implicit Methods” page: how accurate a user Jacobian has to be, and how one tight relative tolerance tightens the BDF and Radau Newton iterations for every variable.
“Implicit Methods” page: where CyRK’s implicit methods deliberately differ from SciPy’s.
New “Integration Methods” page: the order, stages, error estimate, interpolant, and memory of every method, guidance on which methods suit which problems, and work-precision measurements (diffeq calls and wall time to reach a given error) on the Lorenz, Arenstorf, Pleiades, Van der Pol, and linear oscillator problems. The script behind the measurements is “Benchmarks/explicit_work_precision.py”.
README, “C++ API”, “Numba”, and “Dense Output and
t_eval” pages list the new methods and their memory use and interpolant costs.
v0.19.X¶
v0.19.4 (2026-10-08)¶
Fixes¶
An event whose root finder failed stopped Python interpreter (or, from C++, threw
std::out_of_rangeout of the solver).CyrkErrorMessageshad no message forARGUMENT_ERROR,OPTIMIZE_SIGN_ERROR,OPTIMIZE_CONVERGENCE_ERROR, orEVENT_SETUP_FAILED, andCySolverResult::update_statuslooked messages up with.at. These codes now have messages, and the integration ends unsuccessfully with the root finder’s code as its status.New
c_get_error_message(code)(“c_common.hpp”, cimport fromCyRK.cy.common) looks a message up without throwing, falling back to a generic “Unknown error code” message. CyRK’s own lookups use it; C++ and Cython callers should prefer it overCyrkErrorMessages.at.
CyRK.get_error_message(code)raised aKeyErrorfor an integer code and never returned a message. It now returns the code’s message.
v0.19.3 (2026-10-06)¶
Fixes¶
Reading
toryof apysolve_ivpresult whose Python diffeq raised an error would crash Python with an access violation.WrapCySolverResult.tandynow read the result’s current storage on every access, return empty arrays ((0,)and(num_dy, 0)) when it holds nothing.
v0.19.2 (2026-10-04)¶
Fixes¶
pysolve_ivp: an exception raised by the Python diffeq or by an event function is now raised to the caller. The C++ solvers call these functions through anoexcepthook, so before this fix Python printed “Exception ignored in: ‘CyRK.cy.pysolver.PySolver.diffeq’” and the integration went on with the previous step’s derivative, reporting success with a wrong solution (an event that raised was counted as having fired).PySolvernow stores the exception, stops the solver (statusPYTHON_FUNCTION_ERROR, the step in progress finishes on NaN rates without saving data), and raises it once the solver returns; the same holds for aKeyboardInterrupt, which now stops a long integration, and for the dense-outputcallandcall_vectorizeof a solution with extra outputs, which evaluate the diffeq again. A diffeq that returns fewer thannum_y + num_extravalues raises aValueErrorinstead of being read past its end.CySolverBase::set_external_error(error_code)is the C++ hook behind this: it stops the integration from outside the solver, and the status it sets is not overwritten by the step in progress.
LSODA accepted steps taken with NaN rates and reported success with NaN states. Its weighted norms (
vmnorm,fnorm,bnorm) usedfmax, which drops a NaN argument, so a NaN correction measured zero and passed both the corrector’s convergence test and the local error test. The norms now propagate NaN, so such a step is rejected as with every other method.LSODA no longer creeps forward without end once its step falls to the spacing between numbers at t (which NaN or inf rates force, and which inf rates already did before the fix above, until the step limit set by the available memory). ODEPACK only counts such a step (
nhnil) and goes on. CyRK’s LSODA now fails withSTEP_SIZE_ERROR_SPACING, as the other methods do.
Tests¶
Tests/D_PySolver_Tests/test_f_pysolve_failures.py: exceptions from the diffeq (every method, at the initial state, withpass_dy_as_argandargs, during a dense call with extra outputs, aKeyboardInterrupt, a reused solver afterwards) and from events reach the caller; a short return raises; NaN and inf rates end every method’s integration unsuccessfully, and LSODA’s saved states stay finite.
v0.19.1 (2026-09-15)¶
Fixes¶
Reading a solution’s dense output is now safe from several threads at once when the problem has extra outputs. The interpolant does not carry extra outputs, so each read (
CySolverResult::callandcall_vectorize) evaluates the diffeq once more at the interpolated state, and it did so by borrowing the retained solver’s current-state arrays (offload_to_temp, writey_nowandt_now, run the diffeq, readdy_now,load_back_from_temp). Reads stay thread safe only if the diffeq and its pre-eval function also only read their arguments. Solutions of Python diffeqs (pysolve_ivp) still go through the solver’s arrays and must not be read from several threads.
Tests¶
CyRK.cy.parallel_test.run_dense_output_threads_test(num_threads, num_repeats)solves a Lorenz problem with extra outputs once and reads its dense output from several C++ threads at once, counting reads that differ from a serial read.test_dense_output_read_from_several_threadsrequires zero.
v0.19.0 (2026-09-08)¶
New¶
c_cysolve_batch(C++, “CyRK/cy/c_parallel.hpp”; cimport fromCyRK.cy.parallel): solves a vector ofc_CySolveJobs, each with its ownCySolverResult, acrossstd::threadworkers. The “Parallelization” documentation page provides more information.CyRK.cy.parallel_test.run_parallel_benchmark(num_threads, num_runs, t_end)times a batch of Lotka-Volterra solves so the threading crossover can be measured on any machine. The “Parallelization” page reports the measurements from one machine and the rules of thumb drawn from them (threading pays once time per job times number of jobs reaches a few milliseconds; scaling to many threads needs jobs of roughly 100 us or longer).
Fixes¶
Fixed the macOS wheels on PyPI, which could not be imported unless an OpenMP run time happened to exist at the path used on the build machine (
Library not loaded: @rpath/libomp.dylib). The wheels were built outside ofcibuildwheel, so nothing bundled the library they linked to. Every earlier macOS wheel back to at least v0.10.1 was affected.
Build¶
Dropped the OpenMP compile and link flags. CyRK never used it. The solvers are
nogiland thread safe so it can be parallized externally without the OpenMP support. The wheels no longer link to (or have to bundle)libomp,libgomp, orvcomp140, and a source build on macOS no longer needs brew’sllvmandlibomp.CyRK.cy.prange_testwas replaced byCyRK.cy.parallel_test, which drives a batch of solves through the new C++ thread helper described under “New”.
Merged
_build_cyrk.pyintosetup.py. The cmdclass hook was a leftover from the 2022 move topyproject.toml;setup.pyhas declared the extensions since v0.2.4 (the only way setuptools can mark a wheel as platform specific), so the hook was redundant and, throughpy-modules, was installing_build_cyrkas a top-level module in users’ site-packages.The macOS arm64 wheels are now built by
cibuildwheelalongside the Linux and Windows wheels. Every wheel is installed into a fresh environment and CyRK’s built-in solver checks are run before the upload job can start. Free-threaded CPython wheels are skipped because numba does not ship them currently.The wheel workflow only uploads to PyPI for a published release, or when its manual
uploadinput is set, so it can be run against a branch first.
Tests¶
The macOS test workflow now installs CyRK with clang through
setup-python, same as linux and windows workflows do (and the same toolchain the wheels are built with). The conda environment and the brewllvm/libompsteps have been removed.
Conda-Forge¶
The recipe no longer lists
vcomp14,llvm-openmp, orlibgompin its host or run requirements.
Documentation¶
README: the macOS install section no longer asks for Homebrew’s
llvmandlibomp; each platform’s default compiler works.“Parallelization” page: explains that it is the module containing the
prangeloop, not CyRK, that has to be compiled with OpenMP, and lists the flags for MSVC, GCC, and Apple clang.Demos/jupyter_cyhack.pyadds OpenMP flags to%%cythoncells only where the compiler supports them (Homebrewlibompon macOS; MSVC and GCC out of the box) and honorsCYRK_DEMO_NO_OPENMP; without OpenMP the cells still compile with serialprangeloops.
v0.18.X¶
v0.18.1 (2026-08-18)¶
Dependencies¶
Bumped NumPy upper version pin from <2.4 to <2.6 for both runtime and build.
v0.18.0 (2026-08-17)¶
New Implicit Integration Methods:¶
Radau: an implicit Runge-Kutta method of the Radau IIA family of order 5. It is a C++ port of SciPy’s
scipy/integrate/_ivp/radau.py.Like BDF, it is available from
cysolve_ivp,pysolve_ivp, andnbsolve2_ivp, and supports dense output,t_eval, events, extra output, solution reuse, backward integration, and per-variable tolerance arrays.Unlike BDF and LSODA this is a single-step method, so it carries no solution history and changes its step size without having to rescale anything. That makes it the strongest of the three when a stiff problem changes character sharply: on the new Robertson benchmark it reaches the end in 165 steps where BDF needs 215 and LSODA needs 250.
Added complex dense LU factorization to “c_lu.hpp(cpp)” (the equivalents of LAPACK’s zgetrf and zgetrs) for Radau’s complex iteration matrix. The real and complex routines now share one implementation rather than duplicating the algorithm.
LSODA: an Adams / BDF method that monitors the problem as it integrates and switches between the non-stiff Adams formulas and the stiff BDF formulas on its own.
It is built on a lightly modified copy of the C translation of ODEPACK’s LSODA that ships with SciPy, driven one step at a time so that CyRK keeps control of the solution storage, the events, and the
t_evalinterpolation. See the newThird-Party Codesection of “LICENSE.md” for the notices, and please cite ODEPACK if you use this method.Like BDF, it is available from
cysolve_ivp,pysolve_ivp, andnbsolve2_ivp, and supports dense output,t_eval, events, extra output, solution reuse, backward integration, and per-variable tolerance arrays.Added three options that only LSODA understands. Passing them to any other method now raises an
AttributeErrorrather than being ignored.min_step- the smallest step size LSODA is allowed to take.lbandanduband: the bandwidth of the Jacobian. Declaring a bandwidth on a large system whose variables only couple to their neighbors is a substantial speed up.
Two bugs in the upstream C translation of LSODA were corrected in CyRK’s copy (both are noted at the top of “c_lsoda.hpp”): the user’s minimum step size was stored in a local variable rather than in the common block, so the option was silently discarded, and
bnormwas handed the banded Jacobian without the row offset that it was written to.
BDF: an implicit multi-step method based on the backward differentiation formulas, with the order varying automatically between 1 and 5. It is a C++ port of SciPy’s
scipy/integrate/_ivp/bdf.pyand includes the accuracy enhancement from the modified (NDF) formulas. This method is ideal for stiff ODEs (an example shows a decrease from 46,451 to 348 steps when compared to RK45).It is available everywhere the existing methods are (
cysolve_ivp,pysolve_ivp, andnbsolve2_ivp) and supports everything they do: dense output,t_eval, events, extra output, solution reuse, backward integration, and per-variable tolerance arrays.Each step solves its algebraic system with a simplified Newton iteration. The iteration matrix is factorized with CyRK’s own LU routines and reused across steps until the step size, the order, or a convergence failure forces a refactorization.
BDF holds the Jacobian and its factorization as dense matrices, so its memory grows with the square of the number of dependent variables. That footprint is checked against
max_ram_MBduring setup, which reports a memory allocation error rather than starting a solve that could not finish in reasonable time.
C++ Backend¶
Prepared the solver base classes for implicit integration methods.
Moved the tolerances (
rtols,atols) and the step size limits (max_step_size,first_step_size) fromRKConfigup toProblemConfig, since every adaptive method needs them.RKConfigis retained as an alias so existing code keeps working, and its long constructor andupdate_propertiesoverload now live onProblemConfig.Moved the tolerance parsing (
p_setup_error_control) and the first step size estimator (p_calc_first_step_size) fromRKSolvertoCySolverBasefor the same reason.Added
CySolverBase::p_finalize_setup, called at the end of setup once the first step size is known. Multi-step methods need it to build their solution history.CySolverDensenow refreshes its interpolation order and its step size from the solver every time its state is set, instead of only when it is constructed. Two new virtuals,set_Q_order_maxandget_dense_base_y_ptr, cover the differences between an interpolant that works forward from the start of a step and one that works backward from the end of it.A non-positive
max_stepis now rejected during setup instead of producing an invalid step size clamp.
Added an optional analytic Jacobian,
JacobianFuncType.cysolve_ivpandbaseline_cysolve_ivptake a newjac_ptrargument at the end of their argument lists; it is unused until an implicit method is selected. When it is null,CySolverBase::p_estimate_jacobianbuilds the Jacobian with adaptive finite differences, following SciPy’snum_jac.Added “c_lu.hpp(cpp)”: dense and banded LU factorization (the equivalents of LAPACK’s dgetrf, dgetrs, dgbtrf, and dgbtrs). These are implemented in CyRK so that it still does not need to link against an external BLAS or LAPACK library.
Added the
JACOBIAN_IS_SINGULAR,NEWTON_CONVERGENCE_ERROR, andLSODA_INTERNAL_ERRORerror codes. They are all added together so that the error code values stay stable.
Fixes¶
Fixed
get_method_strin “numba_solver.py” reporting the wrong method name; its integers did not match theODEMethodenum.Fixed
CySolverResult::solvereporting success for a solve that never ran.Fixed the wheel installing a top level
Testspackage into the user’s site-packages.Fixed every
excludein “MANIFEST.in” silently matching nothing.Fixed a
%dformat specifier being handed asize_tin “events_test.pyx”.Removed three cached pointers in “rk.cpp” that were never read (
l_K_ptrinp_compute_stagesandp_estimate_error,l_K_ptr_index_ptrinset_Q_array).CyRK’s x86-64 builds target AVX2 deliberately, but a CPU without it used to fault with an illegal instruction somewhere inside a compiled extension. Importing CyRK now checks for AVX2 first and raises an
ImportErrorthat says what happened and how to get a build that runs. The check is fail-open: if the CPU’s capabilities cannot be determined the import proceeds.Added
CYRK_NO_AVX2. Setting it builds without AVX2, and leaving it set at run time turns the check above off, so a CPU without AVX2 has a supported route to a working install.Fixed
-mavx2and-mfmabeing passed to the linker rather than the compiler on Linux, where they had no effect on code generation at all.Silenced MSVC’s C4551 and C4018 on Windows builds.
Documentation¶
Added an “Agreement with SciPy” section to the implicit methods page, with two new figures. The first is a work-precision diagram showing that CyRK and SciPy buy accuracy at the same rate for every implicit method and problem tested.
Added “Benchmarks/scipy_implicit_comparison.py”, which regenerates those figures and statistics.
Added a new “Implicit Methods” documentation page covering how to choose between BDF and LSODA, the Jacobian, the cost of these methods, and the LSODA-only options.
Updated “C++_API.md” with the new
cysolve_ivpargument list and the new “c_lu”, “bdf”, “lsoda”, and “c_lsoda” modules.Documented the new error codes in “Status_and_Error_Codes.md”.
Added a
Third-Party Codesection to “LICENSE.md” with the notices for the vendored LSODA code and for the algorithms that are ported from SciPy, along with SciPy’s license. Added the ODEPACK citations to the README.
Tests¶
Added “Tests/H_Implicit_Tests” covering accuracy against analytic solutions, stiff performance, dense output,
t_eval, events, extra output, backward integration, tolerance arrays, solution reuse, step size limits, and the LSODA banded Jacobian.Added the new methods to the existing accuracy test suites.
Made the trimmed RK23 tests deterministic.
Extended the RK23 trimming to “test_a_cysolve_ivp.py”.
Replaced
diffeq_stiffin “test_a_pysolve_ivp.py” with the Robertson problem, which is actually stiff, and used it to check that an explicit method exhausts a step budget that an implicit method finishes comfortably inside.
Performance¶
Added a stiff problem to the performance stack: “Performance/robertson.py” holds the Robertson chemical kinetics problem, the standard benchmark for stiff solvers. None of the existing benchmark problems are stiff, so none of them showed what the implicit methods are for. On this one the explicit methods are held to tiny steps by stability: over the larger time span RK45 needs about 34,600 steps where BDF needs 109 and LSODA needs 140. It is also available to
cysolve_ivpthroughcytesteras differential equation number 11.Added the new integration methods to “Performance/performance.py”.
The legacy
nbsolve_ivpdoes not implement the implicit methods, so its column is left blank for them.The two problems with 10,000 dependent variables are skipped for the implicit methods, since a dense Jacobian of that size would need a 10,000 by 10,000 factorization on every step.
Noted in “Performance.md” that a stiff problem’s step count is set by stability rather than by the error tolerances, which is the case where an implicit method wins despite its higher per step cost.
Benchmarks¶
Made the integration method selectable in “Benchmarks/CyRK - SciPy Comparison.ipynb” through a new
integration_methodsetting. It was hard coded to RK45; it now accepts any of the six methods and dropsnbsolve_ivpfrom the comparison when an implicit one is chosen, since that solver only implements the explicit Runge-Kutta methods. Figures for a method other than RK45 are saved with the method in their file name so they do not overwrite the existing ones.Added the Robertson problem to “Benchmarks/diffeq_builder.py” as
'robertson'so that the notebook has a stiff problem to compare the implicit methods on. Its middle species sits around 1e-5 for the whole integration, so the plot scales it up by 1e4 to keep it visible.Added event functions for the Robertson problem to
cytester, which previously raisedNotImplementedErrorwhen asked for events on differential equation number 11.Fixed the notebook plotting the
nbsolve_ivpresult a second time in place of thenbsolve2_ivpresult.
v0.17.X¶
v0.17.2 (2026-08-15)¶
Fixes¶
Fixed reused solutions silently keeping the previous run’s problem shape.
CySolverResult::setuponly rebuilt the configuration’s derived properties (num_y,num_dy,capture_extra, …) the first time it ran. Callers are allowed to set the source properties directly, whichpysolve_ivpdoes, so on a reuse those derived properties went stale and the second run silently solved the wrong problem. They are now rebuilt on every setup.The most visible symptom was that changing
num_extraon a reusedpysolve_ivpsolution dropped the extra output entirely. That now works.cysolve_ivpwas never affected; it builds its configuration throughupdate_properties, which has always re-initialized.
pysolve_ivpnow raises anAttributeErrorwhen a reused solution is given ay0with a different number of dependent variables, instead of silently returning garbage. The solver’s dependent variable storage is shared with numpy arrays that were built for the previous run, so changing that size is not supported; build a new solver instead.cysolve_ivpshares no storage with Python objects and keeps its ability to be reused across problems of different sizes.
Documentation¶
Documented in “CySolverResult_Reuses.md” what can and can not change between reuses.
Tests¶
Added “Tests/D_PySolver_Tests/test_e_pysolve_reuse_shape.py” covering reuse with a changed
num_y,num_extra, andt_eval, for bothpysolve_ivpandcysolve_ivp.
v0.17.1 (2026-02-23)¶
Package¶
Adds new “numba_c_api_.cpp” to manifest.
v0.17.0 (2026-02-23)¶
Fixes¶
Fixed issue where events may not be checked in pysolve_ivp.
Fixed issue where dense output calls were not working when performing backwards integration.
C++ Backend¶
Changed how dense outputs are constructed so they retain a pointer to the solution instance not the solver.
This will allow dense to survive even if the solver is released. The exception is if
capture_extrais set to true In that case we need to call the diffeq from dense::call so we must keep the reference (all dense are destroyed if the solver is released).
Exposed the
force_retain_solverparameter incysolve_ivp.If set to True (the default) then the solver will be retained at the end of integration, even if it is not necessarily needed. This can avoid issues where the solver is accessed by the user after it has been released.
If set to False (and capture_extra = False or capture_dense = False) then the solver’s memory will be released at the end of integration. This can reduce memory overhead particularly if your problem has a large number of dependent y variables.
Unrolled most of the RK calculations to improve performance.
nbsolve_ivp Changes¶
Implemented a new
nbsolve2_ivpwhich is a numba-safe wrapper to the CySolver C++ backend. This will greatly improve future development by putting all functionality into C++ and just having a light numba wrapper around it. The newnbsolve2_ivpcan havecysolve_ivpfunctionality (like dense outputs) that the currentnbsolve_ivplacks.The current
nbsolve_ivpwill be replaced by this newnbsolve2_ivpin a future release (treating it as experimental for now).Added deprecation warnings and a new
warnings=Truebool to the currentnbsolve_ivp.The result of integration using
nbsolve2_ivpis different than CyRK’s other solvers and there are some important considerations to keep in mind. Please review the new “Numba” documentation.
Benchmarks¶
Added in a repeater inside
cysolve_ivptester so we can more accurately benchmark the integrators performance without also tracking the python wrappers overhead.This led to a huge increase in performance on the benchmarks.
cysolve_ivp is now consistently 100 to 500x faster than scipysolve_ivp`.
Added a benchmark for large number of dependent y variables (y=10_000) to cytester and the SciPy Comparison notebook.
Demos¶
Fixed demos so they properly use cross-platform headers (required ipython hack which is included in the new “Demos/jupyter_cyhack.py”).
Added demo to show cysolve prange.
Documentation¶
Added resets/restarts to the CySolver examples notebook.
Adjusts change log section numbering.
Added brief note in documentation about parallelizing cysolve.
Added document describing memory usage of the C++ structures.
Added document describing performance tips and tricks.
Added a new Numba.md documentation file describing
nbsolve_ivpandnbsolve2_ivp.
Dependencies¶
Bumps max numpy pins to 2.4.x
Adds support for Python 3.14.x
Tests¶
Added tests for
nbsolve2_ivp.Turned back on backwards integration tests that were being skipped.
2025¶
v0.16.X¶
v0.16.1 (2025-12-10)¶
Dependencies¶
CyRK now supports numpy 2.4.x
Repository Changes¶
Changed license to Apache 2.0
Added citation.cff file
Added codemeta.json file
Add GitHub Workflow to automatically update version numbers
Tests¶
Retired MacOS 13 tests.
v0.16.0 (2025-09-24)¶
CyRK now supports Events!¶
New C++
Eventclass which wraps Cython functions and is integrated intoCySolver.pysolve_ivpandcysolve_ivphave new arguments for the user to provide event functions.Added tests and documentation for these new features.
Other New Features¶
Added new
CyRK.optimizepackage with will house various numerical/scientific optimizations tools.To this package, added a Cython wrapped
brentqmethod based off of SciPy’s implementation. (Note this is not properly exposed to python (don’t need to for CyRK but might be a nice thing to add in the future)
Changes¶
Moved Cython wrappers for “common.cpp” to its own file “common.pyx/pxd”; refactored previous “common.cpp/hpp” to “c_common.cpp/hpp”
Improved performance of pysolve_ivp.
Fixes¶
Fixed some incorrect types in cysolver_api wrapper.
v0.15.X¶
v0.15.1 (2025-08-15)¶
Fixes¶
Fixed issue where cysolver would not properly reset in-between reuse runs unless
setupwas explicitly called.
v0.15.0 (2025-08-13)¶
Changes¶
Moved away from using std::optional in integrator configs. It is just not currently supported by cython enough. Causing more headaches than its worth.
This led to a small performance improvement for cysolve_ivp for problems with a low number of integration steps.
Tests¶
Added tests to check on the reuse functionality introduced in v0.14.0.
Fixes¶
Fixed some initialization of C++ object properties to be more efficient.
Other compile warnings were resolved.
v0.14.X¶
v0.14.1 (2025-08-13)¶
Minor documentation fix.
v0.14.0 (2025-08-13)¶
New¶
Reuse mechanism
The major change with this version is a “reuse” functionality that allows users to reuse previous ODE result structures to avoid memory allocations.
Added demos and documentation to showcase how this new reuse functionality works.
Added a demo cell in “1 - Getting Started” notebook to showcase the various functionality of the
WrapCySolverResultobject.Added ReadTheDocs documentation website at: https://cyrk.readthedocs.io/en/latest.
Changes¶
C++ Backend:
Moved to ErrorCodes enum for tracking error codes.
Changed how CySolverResult works:
Transitioned away from using shared pointers.
Instantiating classes requires less arguments. Moving more of the initializations to
setups so that these setup methods can be called later on to change parameters without reallocating the entire object.
Added more checks to look out for memory allocation problems.
Added more checks and error catches to avoid other problems.
Optimized solution storage, solver, and dense output to better fit in typical cache sizes.
Vectors are now pre-allocated with guesstimated sizes at objection creation to reduce the need for subsequent reallocations.
CySolver:
WarpCySolverResult.callnow reshapes the output array.Other arrays are now passed to
cysolve_ivpas vectors. These changes remove the need to pass the size of the vectors to cysolve_ivp.Additional arguments are now passed to
cysolve_ivpas vector[char] now.Former
y0_ptris nowy0_vecand expects a vector[double].Former
t_eval_ptris nowt_eval_vecand expects a vector[double].Former
r_tols_ptris nowrtols_vecand expects a vector[double].Former
a_tols_ptris nowatols_vecand expects a vector[double].
Improved how additional arguments are displayed when
WrapCySolverResult.print_diagnosticsis called.
Other:
Updated benchmark plot to show the new reset results.
Fixes¶
CySolver Backend:
Fixed potential issue where provided t-eval pointer could stop pointing to correct block of memory.
Fixed issue where extra outputs were not getting saved on the first time step.
Fixed potential problem where t_eval indices were being converted to ints. For very large arrays there could be a wrap around bug.
Moved to one vector for dependent y arrays storage and one vector for dy arrays. Pointers added to respective sections of each vector.
Most vectors are now resized and values are changed via assignment rather than being cleared and appended to. This allows for resets to retain the original memory and avoid memory allocations unless absolutely necessary.
PySolver Backend:
Fixed potential issue where the python module may not have gotten decremented.
Removed the PySolver methods from the C++ codebase. Don’t see any reason they can’t live in pure python land.
v0.13.X¶
v0.13.5 (2025-04-09)¶
Fixes¶
Missing files in manifest.
v0.13.4 (2025-04-09)¶
Fixes¶
Fixed *.pyx and *.pxd files not being included in distributions.
v0.13.3 (2025-04-09)¶
Fixes¶
Fixed issue in manifest.
v0.13.2 (2025-04-09)¶
Changes¶
Modified GitHub workflows so that tests are only run on commits when asked.
Fixes¶
Fixed cythonized files that were being included with sdist, causing problems with conda-forge.
v0.13.1 (2025-04-08)¶
Changes¶
Added more debug info during installation.
Fixes¶
Fixed const errors at compile time.
v0.13.0 (2025-04-03)¶
New & Changes:¶
Added support for Python 3.13 and Numpy 2.x
Fixes¶
Fixes memory leak in CySolver (this was mostly effecting pure cython calls; python calls may not have had an issue. Also only when dense output was on).
The fix also led to a fairly big performance boost to
pysolve.
Fixed error in CySolver tester that could cause crashes or incorrect results (only effected some tests and benchmarks).
v0.12.X¶
v0.12.2 (2025-03-27)¶
Re-release to trigger conda build that included dependency fixes.
2024¶
v0.12.X (cont’d)¶
v0.12.1 (2024-12-02)¶
Fixes¶
Tests¶
Added test to check that arrays stay alive after underlying
WrapCySolverResultclass is destroyed.
v0.12.0 (2024-12-02)¶
New & Changes:¶
MAX_STEPcan now be cimported from the top-level of CyRK:from CyRK cimport MAX_STEPChanged uses of
void*tochar*for both diffeq additional args and pre-eval outputs. The signature of these functions has changed, please review documentation for correct usage.Added new diagnostic info display tool to
cysolve_ivpandpysolve_ivpoutput that you can access with<result>.print_diagnostics().
Fixes¶
Fixed issue with
cysolve_ivp(pysolve_ivpdid not have this bug) where additional args are passed to diffeq and dense output is on and extra output is captured.Calling the dense output when extra output is on requires additional calls to the diffeq. However, after integration there is no gurantee that the args pointer is pointing to the same memory or that the values in that memory have not changed.
Best case, this could cause unexpected results as new values are used for additional args; worst case it could cause access violations if the diffeq tries to access released memory.
Now the
CySolverBasemakes a copy of the additional argument structure so it always retains those values as long as it is alive. This requires an additional memory allocation at the start of integration. And it requires the user to provide the size of the additional argument structure tocysolve_ivp.
Tests¶
Documentation:¶
Updated the “Advanced CySolver.md” documentation that was out of date.
v0.11.X¶
v0.11.5 (2024-11-27)¶
New¶
Added a
steps_takentracking variable to the C++ classCySolverResultand the Cython wrappedWrapCySolverResultso that users can see how many steps were taken during integration even when usingt_eval.
v0.11.4 (2024-11-25)¶
C++ Changes
Moved away from stack to heap allocated vectors for arrays that depend on the size of y0. Prior stack allocation required a hard upper limit which was a limitation for some use cases (See GitHub Issue #74).
v0.11.3 (2024-11-18)¶
New¶
Added helper function to allow users to include CyRK headers during installation.
CyRK.get_include()this returns a list which must be appended to your include list in “setup.py”.Some minor performance improvements when using dense output or t_eval.
Added new cysolve_ivp C++ function,
baseline_cysolve_ivp_noreturn, and cython wrapped version,cysolve_ivp_noreturn, that require the storage class as input (then modify it) rather than provide it as output.
C++ Changes¶
Major rework of the C++ Solver backend
The
CySolverResultstorage structure is now the owner of: the solution data, the dense outputs, and the solver itself (before the solver was stand alone). This ensures that the solver is alive for the dense outputs which, depending on settings, may need to make calls to the solver even after the integration is complete.Removed many pointers in favor of direct access of variables. This was due to some variables moving and hanging pointers causing crashes.
Drastically reduced the size of
CySolverDenseand moved its state data to a heap allocated array. This has led to large performance gains whendense_output=Truefor integrations requiring a large number of steps.
num_yandnum_extraare now size_t type instead of unsigned ints.integration methodis not int instead of unsigned int.
Fixes¶
Fixed issue where if t_eval was less than t_end it could cause an access violation.
Fixed issue where dense output was sometimes being created twice when t_eval was provided.
Addressed several compile warnings.
Fixed issue where when t_eval is provided and dense output = true, cysolver may call a dense solution that has moved (hanging pointer).
v0.11.2 (2024-11-12)¶
New¶
Using extra output (via
num_extra) withcysolve_ivpandpysolve_ivpnow works whendense_outputis set to true. CySolverSolution will now make additional calls to the differential equation to determine correct values for extra outputs which are provided alongside the interpolated y values.Added relevant tests.
Other¶
Refactored some misspellings in the cysolver c++ backend.
Fix¶
Fixed missing
np.import_arrayin cysolver backend.
v0.11.1 (2024-11-11)¶
Fixes¶
MacOS was not correctly installing openmp version of the cython object files. Fixed this but…
Issues¶
Cython
prangewas failing (for the array interps) only on MacOS on some versions of Python. Couldn’t figure it out so removing prange for now.
v0.11.0 (2024-11-09)¶
New¶
WrapCySolverResultresult class now provides user access to attributenum_y.
Removed¶
Removed previous
cyrk_odeand older version of theCySolverclass-based solver.The functionality of
cyrk_odeis now handled by the new (as of v0.10.0)pysolve_ivpfunction.The functionality of
CySolveris partly handled by the new (as of v0.10.0)cysolve_ivpfunction.Note that the new cysolve_ivp is a functional approach. A class based approach like the older CySolver class supported is no longer available but could be easy to implement. If there is interest please create a Github issue for it.
Refactors¶
Refactored the new cysolver and pysolver files to remove “New”. This will break imports based on previous versions.
Broke up cysolver and pysolver into different files to isolate each other’s code.
Other¶
Changed the default ordering for diffeq function inputs to follow the scheme dydt(dy, t, y); previously it was dydt(t, y, dy). This affects the
cy2nbandnb2cyhelper functions.Updated performance module to use new methods over old.
Demos¶
Fixed typo in the type of the mixed-type args container.
Updated to work with new refactoring.
Tests¶
Updated tests to use pysolver where cyrk_ode was used.
Changed tolerances and other inputs to try to make some tests faster.
Dependencies¶
Tested that CyRK works with numpy v2.X; but a lot of other packages don’t right now. So setting it as upper limit.
Tested that CyRK can not work with Python 3.13 yet due to numba dependence. See issue
v0.10.X¶
v0.10.2 (2024-11-05)¶
New¶
Added new
interpolate_from_solution_listfunction to help interpolate between multiple solutions across a domain.
Bugs¶
Fixed issue where
CyRK.test_cysolver()used incorrect kind and order of arguments.Fixed MacOS compile issues when using OpenMP (for both x86-64 and arm64 macos).
Fixed issue where MacOS was failing certain tests.
Building new wheels to fix Github issue #62.
Tests¶
Added tests to check all built in testers.
v0.10.1 (2024-07-25)¶
C++ Backend¶
Changed optional args from double pointer to void pointers to allow for arbitrary objects to be passed in.
Added description of this feature to “Documentation/Advanced CySolver.md” documentation and “Demos/Advanced CySolver Examples.ipynb” jupyter notebook.
Allow users to specify a “Pre-Eval” function that can be passed to the differential equation. This function should take in time, y, and args and update an output pointer which can then be used by the diffeq to solve for dydt.
cysolve_ivp¶
Change call signature to accept new
pre_eval_funcfunction.Added more differential equations to tests.
Added tests to check new void arg feature.
Added tests to check new pre-eval function feature.
MacOS¶
Going back to GCC for C and C++ compile instead of clang (ran into inconsistent test failures with clang).
v0.10.0 (2024-07-17)¶
C++ Backend¶
This version of CyRK introduces a major rework of the backend integrator which is now written in pure C++.
CySolver is now a Cython wrapper to this C++ integrator which can be accessed via Python.
Access this function by using
from CyRK cimport cysolve_ivp(this must be done within Cython).The plan is to replace CyRK’s older
CySolverwith this function.
There is now a new PySolver version of this wrapper that allows a user to pass a python function to the C++ backend.
Access this function by using
from CyRK import pysolve_ivp.This is designed as a drop-in-place replacement for SciPy’s
solve_ivp.The plan is to replace CyRK’s older
cyrk_odewith this function.
Implemented Dense Output and Improved t_eval for new C++ backend¶
Both
pysolve_ivpandcysolve_ivpnow utilize a much more accurate interpolator whent_evalis provided.Users can now also request the interpolators be saved with the data, enabling Dense Output functional calls.
This closes #45.
Note that these improvement was not made for
nbsolve_ivp,cyrk_ode, orCySolvermethods. See below to learn about these methods’ deprecation.
Added tests, documentation, and demos describing these features.
Deprecating Older CyRK Methods¶
The new C++ backend is more flexible, faster, and allows for easy additions of new features. It is common across the cython-only, python, and njit-safe numba solvers. Therefore making a change to it propagates to all three solvers - allowing for easier maintenance and new features. For these reasons, the older
cyrk_ode,CySolver, andnbrk_odeare now marked as deprecated. No new features will be implemented for those functions and they will be removed in the next major release of CyRK.Deprecated
cyrk_odeDeprecated
CySolverWarnings will be issued if these functions are used in this release. To suppress these warnings set
raise_warningsto False in the respective function calls.
CySolver¶
Changed error message to use a stack-allocated char-array and associated pointer.
Added new argument to constructor
raise_warnings(default: True) to allow users to suppress warnings.
cyrk_ode¶
Added new argument to constructor
raise_warnings(default: True) to allow users to suppress warnings.
WrapCySolverResult¶
cysolve_ivpandpysolve_ivpnow return a class structure that stores the result of the integration along with some meta data. The accessible attributes are:cysolve_ivpsCySolverResult:success (bool): Flag if the integration was successful.
message (str): Message to give a hint on what happened during integration.
error_code (int): Additional error/status code that hints on what happened during integration.
size (int): Length of time domain.
y (float[:, :]): 2D Float Array of y solutions (and any extra output).
t (float[:]): 1D Float Array of time domain at which y is defined.
nbsolve_ivp¶
The older
nbrk_odehas been refactored tonbsolve_ivpto match the signature of the new cython-based functions (and scipy’s solve_ivp).The output of
nbsolve_ivpis now a named tuple that functions similar to theWrapCySolverResult
Memory Management¶
Changed exit code when memory can not be allocated.
Changed some heap allocated arrays in
CySolverto be stack allocatedThis change limits the total number of y-dependent variables and extra output that is tracked to 50. This size is easy to change. If your use case requires a larger size then open an issue and an alternative can be discussed.
Converted the underlying storage arrays for
CySolverto LinkedLists arrays.
Bug Fixes¶
Fixed issue where the Cython-based solvers might use the incorrect memory freeing function.
Other Changes¶
Moved from GCC to Clang on MacOS builds. There was a new problem that appeared with GCC’s linker and could not find a working solution. The original move away from clang was done to support openMP multiprocessing. CyRK does not currently use that so the switch back should be okay.
Known Issues¶
There is an occasional bug with backwards integration on pysolve_ivp and cysolve_ivp. See Github Issue #56.
v0.9.X¶
v0.9.0 (2024-05-22)¶
Major Changes¶
Shifted from using the Python-based
PyMem_Alloc,PyMem_Freeto c-basedmalloc,free.CySolver
_solvemethod is now gil-free.This has led to a 35%–230% speed boost at low values of steps (faster start up).
Other Changes¶
CI will now build x64-86 and arm64 wheels for MacOS (change suggested by @dihm in #49).
Did have to use this
nomklworkaround which may cause problems. TBD.
v0.8.X¶
v0.8.8 (2024-04-30)¶
New Features¶
Added
utils.free_memfunction to free memory so that future changes to the memory allocation system will call the proper free function that works with theutils.allocs.
Changes¶
Changed all instances of
PyMem_Freeto newfree_memfrom the utils.
v0.8.7 (2024-04-28)¶
Updated manifest and rebuilt wheels.
v0.8.6 (2024-02-13)¶
Major Changes¶
Added support for Python 3.12.
Converted
CySolver’srk_stepmethod into a pure-c implementation to allow for further optimizations.Changed all files to compile with c rather than c++.
Had to change cpp_bools to bints to make this change.
Bug Fixes¶
Fixed issue where CyRK was not installing on MacOS due to issue with LLVM and OpenMP.
Have opted to go to gcc for macOS install due to issues with OpenMP and clang.
Fixed incorrect type for rk method in CySolver (should eliminate some compile warnings).
Fixed issue in benchmark where incorrect results were being displayed for CySolver.
2023¶
v0.8.X (cont’d)¶
v0.8.5 (2023-10-27)¶
Other Changes¶
Improved t-eval setter and resetter in
CySolver
Bug Fixes¶
Fixed bug where incorrect memory was being accessed whenever
CySolverintegration failed (leading to seg fault).
v0.8.4 (2023-10-18)¶
Performance¶
Removed some try/finally blocks, they were largely not needed in
CySolveras allocated memory is released on the class destruction.Cleaned up unused variables in cython-based solvers.
Other Changes¶
Added “force_fail” parameter to
CySolverto force the integrator to fail to test if memory is released properly.CySolverclass pointers now initialize to NULL at the start of init.CySolvernow owns all data that is heap-allocated (via class attributes). This allows better management of data in the event of crashes or integration failures.
Bug Fixes¶
Max number of steps was being performed before extra_output was parsed in
CySolverwhich could lead to incorrect max num steps.Fixed incorrect type for
CySolver.user_provided_max_num_steps.
v0.8.3 (2023-10-05)¶
New Features¶
Added tests to check if memory access violations can occur when
CySolveris resolved many times.Added new cdef methods to
CySolverfor more efficient changes of parameters:CySolver.change_y0_pointer- Changes the y0 pointer without having to pass memoryviews.CySolver.change_t_eval_pointer- Changes the t_eval pointer without having to pass memoryviews.Added way for user to limit RAM usage for cython-bases solvers. This also changed how max number of steps was calculated.
Performance¶
Changing RK variables back to stack-allocated c-arrays rather than malloc arrays.
Improved how
CySolverandcyrk_odeexpected size is calculated and how much it grows with each concat.Files now compile across multiple threads during installation.
Other Changes¶
Moved some common constants for both
CySolverandcyrk_odeout of their files and intocy.common.Added more meaningful memory error messages to cython files.
Memory allocations (or reallocations) are now performed by helper functions in CyRK.utils.
Better future-proofed package structure (mainifests, gitignores, etc.).
Converted most Py_ssize_t to size_t.
Cleaned up a lot of unused variables and imports.
Bug Fixes¶
Fixed potential memory leaks in cython-based solvers when exceptions are raised.
The new safe guards (likely the try/finally blocks) did cause a somewhat sizable hit to performance.
v0.8.2 (2023-09-25)¶
New Features¶
Added a helper flag to control if
CySolver.reset_stateis called at the end of initialization.
v0.8.1¶
New Features¶
Added more interp functions that take pointers as arguments.
Changes¶
Converted interp functions to use each other where possible, rather than having separate definitions.
Cleaned up .pxd file formatting.
Performance¶
Moved some backend functionality for CyRK.interp to pure c file for performance gains.
Bug Fixes¶
Fixed issue with “cy/common.pyx” not having the correct cython flags during compilation.
v0.8.0¶
New Features¶
Added new interp functions that work with c pointers. These can only be cimported.
Added new “CyRK.cy.common.pyx” file for functions that are used by both
cyrk_odeandCySolver.Moved interpolation functionality into
CyRK.cy.common. Restructuredcyrk_odeandCySolverto use this new function for interpolations.
Changes¶
Refactored many
CySolverinternal attributes to reflect to change from memoryviews to pointers. The most important ones for the user are:CySolver.y_new_view->CySolver.y_ptrCySolver.dy_new_view->CySolver.dy_ptrCySolver.t_new->CySolver.t_nowCySolver.arg_array_view->CySolver.args_ptr
Changed RK constants back to c arrays initialized with PyMem_Malloc. The memory for these arrays are setup in the cython-based solvers. Afterwards, there are helper functions in
CyRK.rkto populate the arrays with correct values.Moved to a more generalized scheme for compiling cython files. See “cython_extensions.json”, “_build_cyrk.py”, and “setup.py” for details.
Performance¶
Transitioned many arrays from numpy to c arrays allocated with PyMem_Malloc, etc. These changes led to a significant performance boost for cython-based solvers.
Copied some performance lessons that were learned from the cython-based solvers to the numba-based nbrk_ode.
v0.7.X¶
v0.7.1¶
Changes¶
Changed cyrk_ode to match the format used by CySolver for its rk_step.
Performance¶
Minor calculation taken out of tight inner loops in cython-based solvers.
Bug Fixes¶
Added back noexcepts to dabs functions used by cyrk_ode that were mistakenly removed in final dev commit of v0.7.0.
Fixed issue where cython-based solvers could overshoot t_span[1].
Fixed issue where interp functions would give wrong result when requested x was between x_array[0] and x_array[1].
Fixed issue where interp functions would give wrong results if requested x was negative and x_array was positive (or vice versa).
The use of carrays for RK constants led to floating point rounding differences that could impact results when step sizes are small.
Converted RK constants to numpy arrays which seem to handle the floats much better.
Also changed the interaction with these variables to be done solely through constant memoryviews. This may provide a bit of a performance boost.
v0.7.0¶
Major Changes¶
Added support for Cython 3.0.0
Added
noexceptto pure cython functions to avoid a potential python error check.
New Features¶
Added the ability to pass arrayed versions of rtol and atol to both the numba and cython-based solvers (cyrk_ode and CySolver).
For both solvers, you can pass the optional argument “rtols” and/or “atols”. These must be C-contiguous numpy arrays with float64 dtypes. They must have the same size as y0.
Added tests to check functionality for all solvers.
This resolves Issue #1.
Added new optional argument to all solvers
max_num_stepswhich allows the user to control how many steps the solver is allowed to take.If exceeded the integration with fail (softly).
Defaults to 95% of
sys.maxsize(depends on system architecture).
New
CySolver.update_constantsmethod allows for significant speed boosts for certain differential equations.See test diffeqs, which have been updated to use this feature, for examples.
Other Changes¶
Improved documentation for most functions and classes.
To make more logical sense with the wording,
CySolver.size_growthsnow gives one less than the solver’s growths attribute.Cleaned up status codes and created new status code description document under “Documentation/Status and Error Codes.md”
Fixed compile warning related to NPY_NO_DEPRECATED_API.
Converted RK variable lengths to Py_ssize_t types.
Changed default tolerances to match scipy: rtol=1.0e-3, atol=1.0e-6.
Performance¶
Various minor performance gains for cython-based solvers.
Moved key loops in
CySolverinto self-contained method so that gil can be released.New
CySolver.update_constantsmethod allows for significant speed boosts for certain differential equations.
Bug Fixes:¶
Fixed potential seg fault when accessing
CySolver’s arg_array_view.Fixed potential issue where
CySolver’s first step size may not be reset when variables that affect it are.Fixed missed declaration in
cyrk_ode.Fixed bug where the state reset flag was not being passed from
CySolver.solvewrapper method.
v0.6.X¶
v0.6.2¶
New Features¶
Added
auto_solvekey word toCySolverclass. This flag defaults to True. If True, then the solver will automatically callself.solve()after initialization.Added new parameter change functions to
CySolverso that certain parameters can be changed after the class is initialized for a performance boost.Look for the “self.change_
” methods in cysolver.pyx/pxd. There is a main change method, CySolver.change_parameterswhich allows you to change multiple parameters at once.
Bug Fixes:¶
Fixed issue where
CySolvercould give incorrect results if thesolve()method was called multiple times on the same instance.Removed extraneous code from
CySolver.__init__.Changed several cython integer variables to all use Py_ssize_t types. Corrected type conversions.
v0.6.1¶
New Features¶
Added top level parameters (like
MAX_STEP) used inCySolvertocysolver.pxdso they can be cimported.Added new argument to
array.interpandarray.interp_complex:provided_jthe user can provide ajindex, allowing the functions to skip the binary search.Added new function
interpjto array module that outputs the interpolation result as well as thejindex that was found.
Bug Fixes¶
Fixed issue with array tests not actually checking values.
Other Changes¶
Reordered tests since numba tests take the longest.
Added
initializedcheck=Falseto the array module compile arguments.
v0.6.0¶
New Features¶
CyRKnow works with python 3.11.Created the
CySolverclass which is more efficient than thecyrk_odefunction.Solves issue 28
New functions in
CyRK.cy.cysolvertestto help test and check performance ofCySolver.
Performance¶
Removed python lists from
cyrk_odeleading to an increase in performance of 15–20%.Solves issue 27
Bug Fixes¶
Fixed compile error with
cyrk_ode“complex types are unordered”.This was not a problem before so likely something has changed in newer cython versions.
Fixed missing declarations for variables in
cyrk_ode.Fixed potential problems during installation where paths may be incorrect depending on OS.
v0.5.X¶
v0.5.3¶
Performance¶
Removed dynamic optional arguments from
cyrk_ode. Now it checks if those arguments are set to None.
Other Changes¶
Changed
cyrk_odearguments to const to avoid memoryview buffer problems. (Change made by David Meyer)
v0.5.2¶
Fixed issues with MacOS wheel build during CI.
v0.5.1¶
Fixed issues with MacOS wheel build during CI.
v0.5.0¶
New Features¶
cyrk_odenow supports both float and complex-typed y and dydt functions.Resolves issue 3). (Feature added by David Meyer)
Performance¶
Converted various ints to
shorts,chars, orPy_ssize_t.Py_ssize_tis recommended by Cython for loop integers to better support 64-bit architecture.Added custom interpolation functions which, depending on the size of the array, can be up to 10x faster than numpys.
Removed unnecessarily variables from
cyrk_ode.Had to turn off
fastmathfornbrk_ode. See issue 24. This negatively impacted the numba integrator’s performance by around 5%.
Other Changes¶
Refactored, cleaned up, and added comments and docstrings to
cyrk_ode.Changed both
nbrk_odeandcyrk_odetests to use pytest parameterization.Changed the accuracy test for both
nbrk_odeandcyrk_odeto check against a known function.Added openmp dependence during compile time to allow for the use of
prange.Moved
cyrk_ode’s Runge-Kutta constants to a separate moduleCyRK.rk.
Bug Fixes¶
Fixed issue (for
nbrk_odeandcyrk_ode) where incorrect step size could be used due to bad minimum step check (see issue 20).
v0.4.X¶
v0.4.0¶
New Features¶
Added the ability to save intermediate (non-dependent y) results during integration for
nbrkandcyrkode solver.See
Documentation/Extra Output.mdfor more information.
Performance¶
Minor performance improvements to
cyrk_ode(switch to c++ compiler and some related functionality)The new feature that saves intermediate results during integration had a minor impact on performance (even when not using the feature). However, it is within most tests margin of error.
v0.3.X¶
v0.3.0¶
Bug Fixes¶
nbrk_odefixesImproved the storage of results during integration, greatly reducing memory usage. This provides a massive increase in performance when dealing with large time spans that previously required the processor to search outside its cache during integration.
This fixes issue 5.
Performance Improvements¶
Various improvements to
nbrk_odemake it about 200% faster on small time-spans and over 30x+ faster on large timespans.Improvements to
cyrk_odeprovided a modest (~5%) performance increase.
Other Changes¶
Helper functions now have an additional optional kwarg
cache_njitwhich is set toFalsebut can be toggled to enable njit caching.Fixed issue in function timing calculation used in the benchmark plot.
v0.2.X¶
v0.2.4¶
Bug Fixes¶
Fixed issue in precompiled wheel distribution (issue 9). (Fix made by Caroline Russell)
Other Changes¶
Updated CI workflows to utilize
cibuildwheelfor building binary wheels.
2022¶
v0.2.X (cont’d)¶
v0.2.3¶
Bug Fixes¶
cyrk_odefixesBug in doubling up on the time step in the final inter-step diffeq calculation.
v0.2.2¶
Other Changes¶
Added a performance tracking package to measure CyRK’s performance over time and versions.
v0.2.1¶
New Features¶
Added helper functions
from CyRK import nb2cy, cy2nbwhich convert differential equation argument signatures between the formats required for cyrk and nbrk ode solvers.
Other Changes¶
Added back some commented out tests that were left over from the bug fixed in v0.2.0.
Added tests to check that performs both cyrk and nbrk integrations on larger time domains.
Removed the specific test that looked at the underlying issue fixed in v0.2.0 (this is still checked by other tests).
v0.2.0¶
Bug Fixes¶
Fixed issues with the metadata provided by pyproject.toml.
cyrk_odefixesFixed bug that was causing the ubuntu slowdown and likely other errors
Added a
cabsabsolute value function to ensure that complex numbers are being properly handled whenabs()is called.
nbrk_odefixesFixed warning during numba integration about contiguous arrays.
Fixed issue where variable was referenced before assignment when using nbrk’s DOP853
Performance Improvements¶
cyrk_odeimprovementsIntegrator now selects an output message based on the status code rather than building a string during the integration loop.
Switched the loop order for the final list to ndarray conversion. Before the time domain was being redundantly built y_size times.
Other Changes¶
pyproject.toml provides more constrained package list rather than an open search.
Added back ubuntu tests and publishes to GitHub workflows.
v0.1.X¶
v0.1.3¶
Fixed a broken example in the readme documentation.
Added better quick tests for both the numba and cython versions.
Added
SciPydependency that was missing (required for numba integrator).Increased the lower limit on
numpypackage version (to fix issue 7) and removed the upper limit version.Removed python 3.7 as a supported version.
Updated graphic in readme.
Converted over to using
pyproject.tomlinstead ofsetup.pyremoved
version.pyfrom project folder.
v0.1.2¶
Made the calling argument for the numba solver more consistent with the cython one by letting first_step==0 be equivalent to == None
v0.1.1¶
Corrected issues with installation
Improved GitHub workflows