ode 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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