ode 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 268ad106e9a7617020dd7ee6d9cf540b694d2cfe
4
+ data.tar.gz: 5e8c6e7fc50b16cf2eee39142e8f72d5cc6998d2
5
+ SHA512:
6
+ metadata.gz: 713a2c92a16b3e9200eab1ed5d2c19f16cd4d0983200ac9a2d754aacca88b2af05315d6277e3e7a0245108b21b809755b6e7fb12d45d5cd2f117fe9263ded02d
7
+ data.tar.gz: 6e9a85ea3afbd29063e43e25e01d3ac3d7f6becda3ee6ad0e5643d862f37151680947fc79042e90f09eb95ed4c28e0202cf4b66a2ec3fab90f0692e435481bdb
@@ -0,0 +1,37 @@
1
+ *.gem
2
+ *.rbc
3
+ *.o
4
+ *~
5
+ *.so
6
+ /.config
7
+ /coverage/
8
+ /InstalledFiles
9
+ /pkg/
10
+ /spec/reports/
11
+ /test/tmp/
12
+ /test/version_tmp/
13
+ /tmp/
14
+
15
+ ## Specific to RubyMotion:
16
+ .dat*
17
+ .repl_history
18
+ build/
19
+
20
+ ## Documentation cache and generated files:
21
+ /.yardoc/
22
+ /_yardoc/
23
+ /doc/
24
+ /rdoc/
25
+
26
+ ## Environment normalisation:
27
+ /.bundle/
28
+ /lib/bundler/man/
29
+
30
+ # for a library or gem, you might want to ignore these files since the code is
31
+ # intended to run in multiple environments; otherwise, check them in:
32
+ # Gemfile.lock
33
+ # .ruby-version
34
+ # .ruby-gemset
35
+
36
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
37
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in oderb.gemspec
4
+ gemspec
@@ -0,0 +1,17 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ode (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (10.3.2)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ bundler (~> 1.5)
16
+ ode!
17
+ rake
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Naoki Nishida
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,32 @@
1
+ # Ode
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/ode.svg)](http://badge.fury.io/rb/ode)
4
+
5
+ An ODE solver package for Ruby users.
6
+ Ode is a the wrapper for [ODEPACK](https://computation.llnl.gov/casc/odepack/) and may perform as well as scipy.integrate.odeint and other wrappers.
7
+
8
+ ## Installation
9
+ ```
10
+ gem install ode
11
+ ```
12
+
13
+ ## Examples
14
+ ```
15
+ require 'ode'
16
+
17
+ f = Proc.new{|t, y, fargs|
18
+ p, r, b = fargs[:p], fargs[:r], fargs[:b]
19
+ [ -p*y[0] + p*y[1],
20
+ -y[0]*y[2] + r*y[0] - y[1],
21
+ y[0]*y[1] - b*y[2]
22
+ ]
23
+ }
24
+
25
+ solver = Ode::Solver.new(f).init(0, [0, 0, 0]).f_args({p: 10, r: 28, b: 8/3}).
26
+ solver.integrate(3.0) #integrate f from t=0 to t=3.0
27
+ ```
28
+
29
+ ## License
30
+
31
+ All files under ext/ode/odepack are from scipy.integrate (originally from ODEPACK), and distributed under [SciPy License](https://github.com/domitry/ode/blob/master/SciPy-License.txt).
32
+ All the other files are distributed under [the MIT License](https://github.com/domitry/ode/blob/master/MIT-License.txt).
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ require 'rake/extensiontask'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+ Bundler.setup(:default, :development)
6
+
7
+ Rake::ExtensionTask.new do |ext|
8
+ ext.name = 'ode'
9
+ ext.ext_dir = 'ext/ode'
10
+ ext.lib_dir = 'lib'
11
+ ext.source_pattern = "**/*.{f, c, h}"
12
+ end
@@ -0,0 +1,30 @@
1
+ Copyright (c) 2001, 2002 Enthought, Inc.
2
+ All rights reserved.
3
+
4
+ Copyright (c) 2003-2012 SciPy Developers.
5
+ All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are met:
9
+
10
+ a. Redistributions of source code must retain the above copyright notice,
11
+ this list of conditions and the following disclaimer.
12
+ b. Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in the
14
+ documentation and/or other materials provided with the distribution.
15
+ c. Neither the name of Enthought nor the names of the SciPy Developers
16
+ may be used to endorse or promote products derived from this software
17
+ without specific prior written permission.
18
+
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
24
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30
+ THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,25 @@
1
+ require 'mkmf'
2
+
3
+ $DEBUG = true
4
+ $libs += " -llapack -lcblas -latlas"
5
+
6
+ $INSTALLFILES = [['odepack.h', '$(archdir)'], ['ode.so', '$(archdir)']]
7
+
8
+ path = File.expand_path("../odepack", __FILE__)
9
+ odepack_c = Dir::entries(path).select {|str| str =~ /(.+)\.f/}.map{|str| "odepack/"+str}
10
+ odepack_obj = odepack_c.map{|str| str.gsub(".f", ".o")}
11
+ other_c = %w{ode.c}
12
+ other_obj = other_c.map{|str| str.gsub(".c", ".o")}
13
+
14
+ $objs = odepack_obj + other_obj
15
+ $srcs = odepack_c + other_c
16
+
17
+ create_makefile("ode")
18
+
19
+ Dir.mkdir("odepack") unless Dir.exists?("odepack")
20
+
21
+ if $makefile_created
22
+ text = File.read("Makefile")
23
+ text.gsub!(".mm", ".f")
24
+ File.write("Makefile", text)
25
+ end
@@ -0,0 +1,124 @@
1
+ #include "odepack.h"
2
+ #include <stdlib.h>
3
+ #include <ruby.h>
4
+ #include <stdio.h>
5
+
6
+ static int number_of_params;
7
+ static VALUE func_proc, jac_proc, f_args;
8
+
9
+ #define RESTORE_NEQ(neq) number_of_params=neq;
10
+ #define RESTORE_FUNC(func) func_proc=func;
11
+ #define RESTORE_JAC(func) jac_proc=func;
12
+ #define RESTORE_FARGS(args) f_args=args;
13
+ #define max(v1, v2) (v1 < v2 ? v2 : v1)
14
+ #define min(v1, v2) (v1 < v2 ? v1 : v2)
15
+
16
+ int ode_jacobian_function(int *n, double *t, double *y, int *ml, int *mu, double *pd, int *nrowpd){
17
+ return -1;
18
+ }
19
+
20
+ void ode_function(int *n, double *t, double *y, double *ydot){
21
+ VALUE y_arr = rb_ary_new2(number_of_params), ret;
22
+ int i;
23
+
24
+ for(i=0; i<number_of_params; i++)
25
+ rb_ary_store(y_arr, i, DBL2NUM(y[i]));
26
+
27
+ ret = rb_funcall(func_proc, rb_intern("call"), 3, DBL2NUM(*t), y_arr, f_args);
28
+
29
+ for(i=0; i<number_of_params; i++){
30
+ VALUE num = rb_ary_entry(ret, i);
31
+ ydot[i] = NUM2DBL(num);
32
+ }
33
+ }
34
+
35
+ VALUE excute_lsoda(VALUE self, VALUE t_out, VALUE func, VALUE jac, VALUE init_t, VALUE init_y, VALUE fargs, VALUE opts){
36
+ int itol; double rtol, atol;
37
+ int *iwork; double *rwork;
38
+ int lrw, liw;
39
+ int neq = RARRAY_LEN(init_y);
40
+
41
+ double *y = (double *)ALLOC_N(double, neq);
42
+ double t = NUM2DBL(init_t);
43
+ double tout = NUM2DBL(t_out);
44
+
45
+ int itask = 1; // run solver untill t == tout
46
+ int istate = 1; // this is the first call of the problem
47
+ int iopt = 0; // no optional inputs
48
+
49
+ int jt = 2; // jacobian type indicator. 1: user provides full jacobian. 2: interanally generated jacobian.
50
+ VALUE ret_arr = rb_ary_new2(neq);
51
+ double h0 = 0, hmax =0, hmin = 0;
52
+ int ixpr=0, max_step=0, max_hnil=0, max_ordn=12, max_ords=5;
53
+ int i;
54
+
55
+ RESTORE_NEQ(neq)
56
+ RESTORE_FUNC(func)
57
+ RESTORE_FARGS(fargs)
58
+
59
+ for(i=0; i<neq; i++){
60
+ y[i] = NUM2DBL(rb_ary_entry(init_y, i));
61
+ }
62
+
63
+ // parse options (TODO: accept array)
64
+ itol = NUM2INT(rb_hash_lookup(opts, ID2SYM(rb_intern("itol"))));
65
+
66
+ rtol = NUM2DBL(rb_hash_aref(opts, ID2SYM(rb_intern("rtol"))));
67
+ atol = NUM2DBL(rb_hash_aref(opts, ID2SYM(rb_intern("atol"))));
68
+
69
+ // decide lrw, liw
70
+ liw = 20 + neq;
71
+ iwork = (int *)ALLOC_N(int, liw);
72
+
73
+ if(jac != Qnil){
74
+ jt = 1;
75
+ RESTORE_JAC(jac);
76
+ lrw = max(20+16*neq, 22+9*neq+neq*neq);
77
+ }
78
+ else{
79
+ int ml=0, mu=0; VALUE val;
80
+ if(val = rb_hash_aref(opts, ID2SYM(rb_intern("ml"))) != Qnil)ml = NUM2INT(val);
81
+ if(val = rb_hash_aref(opts, ID2SYM(rb_intern("mu"))) != Qnil)mu = NUM2INT(val);
82
+
83
+ iwork[0] = mu;
84
+ iwork[1] = ml;
85
+ lrw = max(20+16*neq, 22+10*neq+(2*ml+mu)*neq);
86
+ }
87
+
88
+ rwork = (double *)ALLOC_N(double, lrw);
89
+ rwork[4] = h0;
90
+ rwork[5] = hmax;
91
+ rwork[6] = hmin;
92
+
93
+ iwork[4] = ixpr;
94
+ iwork[5] = max_step;
95
+ iwork[6] = max_hnil;
96
+ iwork[7] = max_ordn;
97
+ iwork[8] = max_ords;
98
+
99
+ // run lsoda
100
+ lsoda_(ode_function, &neq, y, &t, &tout, &itol, &rtol, &atol, &itask, &istate, &iopt, rwork, &lrw, iwork, &liw, ode_jacobian_function, &jt);
101
+
102
+ // check error
103
+ if(istate<0){
104
+ rb_raise(rb_eTypeError, "Something went wrong.");
105
+ }
106
+
107
+ for(i=0; i<neq; i++){
108
+ VALUE num = DBL2NUM(y[i]);
109
+ rb_ary_store(ret_arr, i, num);
110
+ }
111
+
112
+ xfree(y);
113
+ xfree(iwork);
114
+ xfree(rwork);
115
+ return ret_arr;
116
+ }
117
+
118
+
119
+ void Init_ode(){
120
+ VALUE ode = rb_define_module("Ode");
121
+ VALUE methods = rb_define_module_under(ode, "Methods");
122
+
123
+ rb_define_singleton_method(methods, "lsoda", excute_lsoda, 7);
124
+ }
@@ -0,0 +1,6 @@
1
+ void lsoda_(void (*f)(int*, double*, double*, double*), int *neq, double *y, double *t, double *tout, int *itol, double *rtol, double *atol, int *itask, int *istate, int *iopt, double *rwork, int *lrw, int *iwork, int *liw, int (*jac)(int*, double*, double*, int*, int*, double*, int*), int *jt);
2
+
3
+ /*int itol = 2; // indicator for error control
4
+ double rtol = 1e-4; // relative error tolerance parameter (scalar or array)
5
+ double atol[3] = {1e-6, 1e-10, 1e-6}; // absolute error tolerance parameter (scalar or array)
6
+ */
@@ -0,0 +1,26 @@
1
+ block data
2
+ c-----------------------------------------------------------------------
3
+ c this data subprogram loads variables into the internal common
4
+ c blocks used by the odepack solvers. the variables are
5
+ c defined as follows..
6
+ c illin = counter for the number of consecutive times the package
7
+ c was called with illegal input. the run is stopped when
8
+ c illin reaches 5.
9
+ c ntrep = counter for the number of consecutive times the package
10
+ c was called with istate = 1 and tout = t. the run is
11
+ c stopped when ntrep reaches 5.
12
+ c mesflg = flag to control printing of error messages. 1 means print,
13
+ c 0 means no printing.
14
+ c lunit = default value of logical unit number for printing of error
15
+ c messages.
16
+ c-----------------------------------------------------------------------
17
+ integer illin, iduma, ntrep, idumb, iowns, icomm, mesflg, lunit
18
+ double precision rowns, rcomm
19
+ common /ls0001/ rowns(209), rcomm(9),
20
+ 1 illin, iduma(10), ntrep, idumb(2), iowns(6), icomm(19)
21
+ common /eh0001/ mesflg, lunit
22
+ data illin/0/, ntrep/0/
23
+ data mesflg/1/, lunit/6/
24
+ c
25
+ c----------------------- end of block data -----------------------------
26
+ end
@@ -0,0 +1,30 @@
1
+ double precision function bnorm (n, a, nra, ml, mu, w)
2
+ clll. optimize
3
+ c-----------------------------------------------------------------------
4
+ c this function computes the norm of a banded n by n matrix,
5
+ c stored in the array a, that is consistent with the weighted max-norm
6
+ c on vectors, with weights stored in the array w.
7
+ c ml and mu are the lower and upper half-bandwidths of the matrix.
8
+ c nra is the first dimension of the a array, nra .ge. ml+mu+1.
9
+ c in terms of the matrix elements a(i,j), the norm is given by..
10
+ c bnorm = max(i=1,...,n) ( w(i) * sum(j=1,...,n) abs(a(i,j))/w(j) )
11
+ c-----------------------------------------------------------------------
12
+ integer n, nra, ml, mu
13
+ integer i, i1, jlo, jhi, j
14
+ double precision a, w
15
+ double precision an, sum
16
+ dimension a(nra,n), w(n)
17
+ an = 0.0d0
18
+ do 20 i = 1,n
19
+ sum = 0.0d0
20
+ i1 = i + mu + 1
21
+ jlo = max0(i-ml,1)
22
+ jhi = min0(i+mu,n)
23
+ do 10 j = jlo,jhi
24
+ 10 sum = sum + dabs(a(i1-j,j))/w(j)
25
+ an = dmax1(an,sum*w(i))
26
+ 20 continue
27
+ bnorm = an
28
+ return
29
+ c----------------------- end of function bnorm -------------------------
30
+ end
@@ -0,0 +1,112 @@
1
+ subroutine cfode (meth, elco, tesco)
2
+ clll. optimize
3
+ integer meth
4
+ integer i, ib, nq, nqm1, nqp1
5
+ double precision elco, tesco
6
+ double precision agamq, fnq, fnqm1, pc, pint, ragq,
7
+ 1 rqfac, rq1fac, tsign, xpin
8
+ dimension elco(13,12), tesco(3,12)
9
+ c-----------------------------------------------------------------------
10
+ c cfode is called by the integrator routine to set coefficients
11
+ c needed there. the coefficients for the current method, as
12
+ c given by the value of meth, are set for all orders and saved.
13
+ c the maximum order assumed here is 12 if meth = 1 and 5 if meth = 2.
14
+ c (a smaller value of the maximum order is also allowed.)
15
+ c cfode is called once at the beginning of the problem,
16
+ c and is not called again unless and until meth is changed.
17
+ c
18
+ c the elco array contains the basic method coefficients.
19
+ c the coefficients el(i), 1 .le. i .le. nq+1, for the method of
20
+ c order nq are stored in elco(i,nq). they are given by a genetrating
21
+ c polynomial, i.e.,
22
+ c l(x) = el(1) + el(2)*x + ... + el(nq+1)*x**nq.
23
+ c for the implicit adams methods, l(x) is given by
24
+ c dl/dx = (x+1)*(x+2)*...*(x+nq-1)/factorial(nq-1), l(-1) = 0.
25
+ c for the bdf methods, l(x) is given by
26
+ c l(x) = (x+1)*(x+2)* ... *(x+nq)/k,
27
+ c where k = factorial(nq)*(1 + 1/2 + ... + 1/nq).
28
+ c
29
+ c the tesco array contains test constants used for the
30
+ c local error test and the selection of step size and/or order.
31
+ c at order nq, tesco(k,nq) is used for the selection of step
32
+ c size at order nq - 1 if k = 1, at order nq if k = 2, and at order
33
+ c nq + 1 if k = 3.
34
+ c-----------------------------------------------------------------------
35
+ dimension pc(12)
36
+ c
37
+ go to (100, 200), meth
38
+ c
39
+ 100 elco(1,1) = 1.0d0
40
+ elco(2,1) = 1.0d0
41
+ tesco(1,1) = 0.0d0
42
+ tesco(2,1) = 2.0d0
43
+ tesco(1,2) = 1.0d0
44
+ tesco(3,12) = 0.0d0
45
+ pc(1) = 1.0d0
46
+ rqfac = 1.0d0
47
+ do 140 nq = 2,12
48
+ c-----------------------------------------------------------------------
49
+ c the pc array will contain the coefficients of the polynomial
50
+ c p(x) = (x+1)*(x+2)*...*(x+nq-1).
51
+ c initially, p(x) = 1.
52
+ c-----------------------------------------------------------------------
53
+ rq1fac = rqfac
54
+ rqfac = rqfac/dfloat(nq)
55
+ nqm1 = nq - 1
56
+ fnqm1 = dfloat(nqm1)
57
+ nqp1 = nq + 1
58
+ c form coefficients of p(x)*(x+nq-1). ----------------------------------
59
+ pc(nq) = 0.0d0
60
+ do 110 ib = 1,nqm1
61
+ i = nqp1 - ib
62
+ 110 pc(i) = pc(i-1) + fnqm1*pc(i)
63
+ pc(1) = fnqm1*pc(1)
64
+ c compute integral, -1 to 0, of p(x) and x*p(x). -----------------------
65
+ pint = pc(1)
66
+ xpin = pc(1)/2.0d0
67
+ tsign = 1.0d0
68
+ do 120 i = 2,nq
69
+ tsign = -tsign
70
+ pint = pint + tsign*pc(i)/dfloat(i)
71
+ 120 xpin = xpin + tsign*pc(i)/dfloat(i+1)
72
+ c store coefficients in elco and tesco. --------------------------------
73
+ elco(1,nq) = pint*rq1fac
74
+ elco(2,nq) = 1.0d0
75
+ do 130 i = 2,nq
76
+ 130 elco(i+1,nq) = rq1fac*pc(i)/dfloat(i)
77
+ agamq = rqfac*xpin
78
+ ragq = 1.0d0/agamq
79
+ tesco(2,nq) = ragq
80
+ if (nq .lt. 12) tesco(1,nqp1) = ragq*rqfac/dfloat(nqp1)
81
+ tesco(3,nqm1) = ragq
82
+ 140 continue
83
+ return
84
+ c
85
+ 200 pc(1) = 1.0d0
86
+ rq1fac = 1.0d0
87
+ do 230 nq = 1,5
88
+ c-----------------------------------------------------------------------
89
+ c the pc array will contain the coefficients of the polynomial
90
+ c p(x) = (x+1)*(x+2)*...*(x+nq).
91
+ c initially, p(x) = 1.
92
+ c-----------------------------------------------------------------------
93
+ fnq = dfloat(nq)
94
+ nqp1 = nq + 1
95
+ c form coefficients of p(x)*(x+nq). ------------------------------------
96
+ pc(nqp1) = 0.0d0
97
+ do 210 ib = 1,nq
98
+ i = nq + 2 - ib
99
+ 210 pc(i) = pc(i-1) + fnq*pc(i)
100
+ pc(1) = fnq*pc(1)
101
+ c store coefficients in elco and tesco. --------------------------------
102
+ do 220 i = 1,nqp1
103
+ 220 elco(i,nq) = pc(i)/pc(2)
104
+ elco(2,nq) = 1.0d0
105
+ tesco(1,nq) = rq1fac
106
+ tesco(2,nq) = dfloat(nqp1)/elco(1,nq)
107
+ tesco(3,nq) = dfloat(nq+2)/elco(1,nq)
108
+ rq1fac = rq1fac/fnq
109
+ 230 continue
110
+ return
111
+ c----------------------- end of subroutine cfode -----------------------
112
+ end