lbfgsb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,122 @@
1
+ #ifndef LBFGSB_RB_LBFGSB_H_
2
+ #define LBFGSB_RB_LBFGSB_H_
3
+
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <float.h>
7
+ #include <math.h>
8
+ #include <string.h>
9
+ #include <time.h>
10
+
11
+ #define TRUE_ (1)
12
+ #define FALSE_ (0)
13
+
14
+ extern int setulb_(long *n, long *m, double *x,
15
+ double *l, double *u, long *nbd, double *f, double *g,
16
+ double *factr, double *pgtol, double *wa, long *iwa,
17
+ char *task, long *iprint, char *csave, long *lsave,
18
+ long *isave, double *dsave);
19
+
20
+ extern int mainlb_(long *n, long *m, double *x,
21
+ double *l, double *u, long *nbd, double *f, double *g,
22
+ double *factr, double *pgtol, double *ws, double *wy,
23
+ double *sy, double *ss, double *wt, double *wn,
24
+ double *snd, double *z__, double *r__, double *d__,
25
+ double *t, double *xp, double *wa, long *index,
26
+ long *iwhere, long *indx2, char *task, long *iprint,
27
+ char *csave, long *lsave, long *isave, double *dsave);
28
+
29
+ extern int active_(long *n, double *l, double *u,
30
+ long *nbd, double *x, long *iwhere, long *iprint,
31
+ long *prjctd, long *cnstnd, long *boxed);
32
+
33
+ extern int bmv_(long *m, double *sy, double *wt, long
34
+ *col, double *v, double *p, long *info);
35
+
36
+ extern int cauchy_(long *n, double *x, double *l,
37
+ double *u, long *nbd, double *g, long *iorder, long *iwhere,
38
+ double *t, double *d__, double *xcp, long *m,
39
+ double *wy, double *ws, double *sy, double *wt,
40
+ double *theta, long *col, long *head, double *p,
41
+ double *c__, double *wbp, double *v, long *nseg,
42
+ long *iprint, double *sbgnrm, long *info, double *epsmch);
43
+
44
+ extern int cmprlb_(long *n, long *m, double *x,
45
+ double *g, double *ws, double *wy, double *sy,
46
+ double *wt, double *z__, double *r__, double *wa,
47
+ long *index, double *theta, long *col, long *head,
48
+ long *nfree, long *cnstnd, long *info);
49
+
50
+ extern int errclb_(long *n, long *m, double *factr,
51
+ double *l, double *u, long *nbd, char *task, long *info, long *k);
52
+
53
+ extern int formk_(long *n, long *nsub, long *ind, long *nenter,
54
+ long *ileave, long *indx2, long *iupdat, long *updatd,
55
+ double *wn, double *wn1, long *m, double *ws,
56
+ double *wy, double *sy, double *theta, long *col,
57
+ long *head, long *info);
58
+
59
+ extern int formt_(long *m, double *wt, double *sy,
60
+ double *ss, long *col, double *theta, long *info);
61
+
62
+ extern int freev_(long *n, long *nfree, long *index,
63
+ long *nenter, long *ileave, long *indx2, long *iwhere,
64
+ long *wrk, long *updatd, long *cnstnd, long *iprint,
65
+ long *iter);
66
+
67
+ extern int hpsolb_(long *n, double *t, long *iorder, long *iheap);
68
+
69
+ extern int lnsrlb_(long *n, double *l, double *u,
70
+ long *nbd, double *x, double *f, double *fold,
71
+ double *gd, double *gdold, double *g, double *d__,
72
+ double *r__, double *t, double *z__, double *stp,
73
+ double *dnorm, double *dtd, double *xstep, double *stpmx,
74
+ long *iter, long *ifun, long *iback, long *nfgv,
75
+ long *info, char *task, long *boxed, long *cnstnd,
76
+ char *csave, long *isave, double *dsave);
77
+
78
+ extern int matupd_(long *n, long *m, double *ws,
79
+ double *wy, double *sy, double *ss, double *d__,
80
+ double *r__, long *itail, long *iupdat, long *col,
81
+ long *head, double *theta, double *rr, double *dr,
82
+ double *stp, double *dtd);
83
+
84
+ extern int prn1lb_(long *n, long *m, double *l,
85
+ double *u, double *x, long *iprint, long *itfile,
86
+ double *epsmch);
87
+
88
+ extern int prn2lb_(long *n, double *x, double *f,
89
+ double *g, long *iprint, long *itfile, long *iter,
90
+ long *nfgv, long *nact, double *sbgnrm, long *nseg, char*word,
91
+ long *iword, long *iback, double *stp, double *xstep);
92
+
93
+ extern int prn3lb_(long *n, double *x, double *f, char *task,
94
+ long *iprint, long *info, long *itfile, long *iter,
95
+ long *nfgv, long *nintol, long *nskip, long *nact,
96
+ double *sbgnrm, double *time, long *nseg, char *word,
97
+ long *iback, double *stp, double *xstep, long *k,
98
+ double *cachyt, double *sbtime, double *lnscht);
99
+
100
+ extern int projgr_(long *n, double *l, double *u,
101
+ long *nbd, double *x, double *g, double *sbgnrm);
102
+
103
+ extern int subsm_(long *n, long *m, long *nsub, long *ind,
104
+ double *l, double *u, long *nbd, double *x,
105
+ double *d__, double *xp, double *ws, double *wy,
106
+ double *theta, double *xx, double *gg, long *col,
107
+ long *head, long *iword, double *wv, double *wn,
108
+ long *iprint, long *info);
109
+
110
+ extern int dcsrch_(double *f, double *g, double *stp,
111
+ double *ftol, double *gtol, double *xtol,
112
+ double *stpmin, double *stpmax,
113
+ char *task, long *isave, double *dsave);
114
+
115
+ extern int dcstep_(double *stx, double *fx, double *dx,
116
+ double *sty, double *fy, double *dy, double *stp,
117
+ double *fp, double *dp, long *brackt, double *stpmin,
118
+ double *stpmax);
119
+
120
+ extern int timer_(double *ttime);
121
+
122
+ #endif /* LBFGSB_RB_LBFGSB_H_ */
@@ -0,0 +1,236 @@
1
+ /**
2
+ * L-BFGS-B is released under the “New BSD License” (aka “Modified BSD License”
3
+ * or “3-clause license”)
4
+ * Please read attached file License.txt
5
+ */
6
+
7
+ #include "blas.h"
8
+ #include "linpack.h"
9
+
10
+ static long c__1 = 1;
11
+
12
+ /**
13
+ * dpofa factors a double precision symmetric positive definite
14
+ * matrix.
15
+ *
16
+ * dpofa is usually called by dpoco, but it can be called
17
+ * directly with a saving in time if rcond is not needed.
18
+ * (time for dpoco) = (1 + 18/n)*(time for dpofa) .
19
+ *
20
+ * on entry
21
+ *
22
+ * a double precision(lda, n)
23
+ * the symmetric matrix to be factored. only the
24
+ * diagonal and upper triangle are used.
25
+ *
26
+ * lda long
27
+ * the leading dimension of the array a .
28
+ *
29
+ * n long
30
+ * the order of the matrix a .
31
+ *
32
+ * on return
33
+ *
34
+ * a an upper triangular matrix r so that a = trans(r)*r
35
+ * where trans(r) is the transpose.
36
+ * the strict lower triangle is unaltered.
37
+ * if info .ne. 0 , the factorization is not complete.
38
+ *
39
+ * info long
40
+ * = 0 for normal return.
41
+ * = k signals an error condition. the leading minor
42
+ * of order k is not positive definite.
43
+ *
44
+ * linpack. this version dated 08/14/78 .
45
+ * cleve moler, university of new mexico, argonne national lab.
46
+ */
47
+ int dpofa_(double *a, long *lda, long *n, long *info)
48
+ {
49
+ long a_dim1, a_offset, i__1, i__2, i__3;
50
+ static long j, k;
51
+ static double s, t;
52
+ static long jm1;
53
+
54
+ a_dim1 = *lda;
55
+ a_offset = 1 + a_dim1;
56
+ a -= a_offset;
57
+
58
+ i__1 = *n;
59
+ for (j = 1; j <= i__1; ++j) {
60
+ *info = j;
61
+ s = 0.;
62
+ jm1 = j - 1;
63
+ if (jm1 < 1) {
64
+ goto L20;
65
+ }
66
+ i__2 = jm1;
67
+ for (k = 1; k <= i__2; ++k) {
68
+ i__3 = k - 1;
69
+ t = a[k + j * a_dim1] - ddot_(&i__3, &a[k * a_dim1 + 1], &c__1, &a[j * a_dim1 + 1], &c__1);
70
+ t /= a[k + k * a_dim1];
71
+ a[k + j * a_dim1] = t;
72
+ s += t * t;
73
+ }
74
+ L20:
75
+ s = a[j + j * a_dim1] - s;
76
+ /* ......exit */
77
+ if (s <= 0.) {
78
+ goto L40;
79
+ }
80
+ a[j + j * a_dim1] = sqrt(s);
81
+ }
82
+ *info = 0;
83
+ L40:
84
+ return 0;
85
+ }
86
+
87
+ /**
88
+ * dtrsl solves systems of the form
89
+ *
90
+ * t * x = b
91
+ * or
92
+ * trans(t) * x = b
93
+ *
94
+ * where t is a triangular matrix of order n. here trans(t)
95
+ * denotes the transpose of the matrix t.
96
+ *
97
+ * on entry
98
+ *
99
+ * t double precision(ldt,n)
100
+ * t contains the matrix of the system. the zero
101
+ * elements of the matrix are not referenced, and
102
+ * the corresponding elements of the array can be
103
+ * used to store other information.
104
+ *
105
+ * ldt long
106
+ * ldt is the leading dimension of the array t.
107
+ *
108
+ * n long
109
+ * n is the order of the system.
110
+ *
111
+ * b double precision(n).
112
+ * b contains the right hand side of the system.
113
+ *
114
+ * job long
115
+ * job specifies what kind of system is to be solved.
116
+ * if job is
117
+ *
118
+ * 00 solve t*x=b, t lower triangular,
119
+ * 01 solve t*x=b, t upper triangular,
120
+ * 10 solve trans(t)*x=b, t lower triangular,
121
+ * 11 solve trans(t)*x=b, t upper triangular.
122
+ *
123
+ * on return
124
+ *
125
+ * b b contains the solution, if info .eq. 0.
126
+ * otherwise b is unaltered.
127
+ *
128
+ * info long
129
+ * info contains zero if the system is nonsingular.
130
+ * otherwise info contains the index of
131
+ * the first zero diagonal element of t.
132
+ *
133
+ * linpack. this version dated 08/14/78 .
134
+ * g. w. stewart, university of maryland, argonne national lab.
135
+ */
136
+ int dtrsl_(double *t, long *ldt, long *n, double *b, long *job, long *info)
137
+ {
138
+ long t_dim1, t_offset, i__1, i__2;
139
+ static long j, jj, case__;
140
+ static double temp;
141
+
142
+ /* check for zero diagonal elements. */
143
+ t_dim1 = *ldt;
144
+ t_offset = 1 + t_dim1;
145
+ t -= t_offset;
146
+ --b;
147
+
148
+ i__1 = *n;
149
+ for (*info = 1; *info <= i__1; ++(*info)) {
150
+ /* ......exit */
151
+ if (t[*info + *info * t_dim1] == 0.) {
152
+ goto L150;
153
+ }
154
+ }
155
+ *info = 0;
156
+
157
+ /* determine the task and go to it. */
158
+ case__ = 1;
159
+ if (*job % 10 != 0) {
160
+ case__ = 2;
161
+ }
162
+ if (*job % 100 / 10 != 0) {
163
+ case__ += 2;
164
+ }
165
+ switch (case__) {
166
+ case 1: goto L20;
167
+ case 2: goto L50;
168
+ case 3: goto L80;
169
+ case 4: goto L110;
170
+ }
171
+
172
+ /* solve t*x=b for t lower triangular */
173
+ L20:
174
+ b[1] /= t[t_dim1 + 1];
175
+ if (*n < 2) {
176
+ goto L40;
177
+ }
178
+ i__1 = *n;
179
+ for (j = 2; j <= i__1; ++j) {
180
+ temp = -b[j - 1];
181
+ i__2 = *n - j + 1;
182
+ daxpy_(&i__2, &temp, &t[j + (j - 1) * t_dim1], &c__1, &b[j], &c__1);
183
+ b[j] /= t[j + j * t_dim1];
184
+ }
185
+ L40:
186
+ goto L140;
187
+
188
+ /* solve t*x=b for t upper triangular. */
189
+ L50:
190
+ b[*n] /= t[*n + *n * t_dim1];
191
+ if (*n < 2) {
192
+ goto L70;
193
+ }
194
+ i__1 = *n;
195
+ for (jj = 2; jj <= i__1; ++jj) {
196
+ j = *n - jj + 1;
197
+ temp = -b[j + 1];
198
+ daxpy_(&j, &temp, &t[(j + 1) * t_dim1 + 1], &c__1, &b[1], &c__1);
199
+ b[j] /= t[j + j * t_dim1];
200
+ }
201
+ L70:
202
+ goto L140;
203
+
204
+ /* solve trans(t)*x=b for t lower triangular. */
205
+ L80:
206
+ b[*n] /= t[*n + *n * t_dim1];
207
+ if (*n < 2) {
208
+ goto L100;
209
+ }
210
+ i__1 = *n;
211
+ for (jj = 2; jj <= i__1; ++jj) {
212
+ j = *n - jj + 1;
213
+ i__2 = jj - 1;
214
+ b[j] -= ddot_(&i__2, &t[j + 1 + j * t_dim1], &c__1, &b[j + 1], &c__1);
215
+ b[j] /= t[j + j * t_dim1];
216
+ }
217
+ L100:
218
+ goto L140;
219
+
220
+ /* solve trans(t)*x=b for t upper triangular. */
221
+ L110:
222
+ b[1] /= t[t_dim1 + 1];
223
+ if (*n < 2) {
224
+ goto L130;
225
+ }
226
+ i__1 = *n;
227
+ for (j = 2; j <= i__1; ++j) {
228
+ i__2 = j - 1;
229
+ b[j] -= ddot_(&i__2, &t[j * t_dim1 + 1], &c__1, &b[1], &c__1);
230
+ b[j] /= t[j + j * t_dim1];
231
+ }
232
+ L130:
233
+ L140:
234
+ L150:
235
+ return 0;
236
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef LBFGSB_RB_LINPACK_H_
2
+ #define LBFGSB_RB_LINPACK_H_
3
+
4
+ #include <math.h>
5
+
6
+ extern int dpofa_(double *a, long *lda, long *n, long *info);
7
+ extern int dtrsl_(double *t, long *ldt, long *n, double *b, long *job, long *info);
8
+
9
+ #endif /* LBFGSB_RB_LINPACK_H_ */
@@ -0,0 +1,29 @@
1
+ require_relative 'lib/lbfgsb/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'lbfgsb'
5
+ spec.version = Lbfgsb::VERSION
6
+ spec.authors = ['yoshoku']
7
+ spec.email = ['yoshoku@outlook.com']
8
+
9
+ spec.summary = 'Lbfgsb.rb is a Ruby binding for L-BFGS-B'
10
+ spec.description = 'Lbfgsb.rb is a Ruby binding for L-BFGS-B'
11
+ spec.homepage = 'https://github.com/yoshoku/lbfgsb.rb'
12
+ spec.license = 'BSD-3-Clause'
13
+
14
+ spec.metadata['homepage_uri'] = spec.homepage
15
+ spec.metadata['source_code_uri'] = 'https://github.com/yoshoku/lbfgsb.rb'
16
+ spec.metadata['changelog_uri'] = 'https://github.com/yoshoku/lbfgsb.rb/CHANGELOG.md'
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = 'exe'
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ['lib']
26
+ spec.extensions = ['ext/lbfgsb/extconf.rb']
27
+
28
+ spec.add_runtime_dependency 'numo-narray', '>= 0.9.1'
29
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'numo/narray'
4
+
5
+ require 'lbfgsb/version'
6
+ require 'lbfgsb/lbfgsbext'
7
+
8
+ module Lbfgsb
9
+ module_function
10
+
11
+ # Minimize a function using the L-BFGS-B algorithm.
12
+ #
13
+ # @param fnc [Method/Proc] Method for calculating the function to be minimized.
14
+ # @param x_init [Numo::DFloat] (shape: [n_elements]) Initial point.
15
+ # @param jcb [Method/Proc] Method for calculating the gradient vector.
16
+ # @param args [Object] Arguments pass to the 'fnc' and 'jcb'.
17
+ # @param bounds [Numo::DFloat/Nil] (shape: [n_elements, 2])
18
+ # \[lower, upper\] bounds for each element x. If nil is given, x is unbounded.
19
+ # @param factr [Float] The iteration will be stop when
20
+ #
21
+ # `(f^k - f^\{k+1\})/max{|f^k|,|f^\{k+1\}|,1} <= factr * Lbfgsb::DBL_EPSILON`
22
+ #
23
+ # Typical values for factr: 1e12 for low accuracy; 1e7 for moderate accuracy; 1e1 for extremely high accuracy.
24
+ # @param pgtol [Float] The iteration will be stop when
25
+ #
26
+ # `max{|pg_i| i = 1, ..., n} <= pgtol`
27
+ #
28
+ # where pg_i is the ith component of the projected gradient.
29
+ # @param maxcor [Integer] The maximum number of variable metric corrections used to define the limited memory matrix.
30
+ # @param maxiter [Integer] The maximum number of iterations.
31
+ # @param verbose [Integer/Nil] If negative value or nil is given, no display output is generated.
32
+ def minimize(fnc:, x_init:, jcb:, args: nil, bounds: nil, factr: 1e7, pgtol: 1e-5, maxcor: 10, maxiter: 15_000, verbose: nil)
33
+ n_elements = x_init.size
34
+ l = Numo::DFloat.zeros(n_elements)
35
+ u = Numo::DFloat.zeros(n_elements)
36
+ nbd = Numo::Int64.zeros(n_elements)
37
+
38
+ unless bounds.nil?
39
+ n_elements.times do |n|
40
+ lower = bounds[n, 0]
41
+ upper = bounds[n, 1]
42
+ l[n] = lower
43
+ u[n] = upper
44
+ if lower.finite? && !upper.finite?
45
+ nbd[n] = 1
46
+ elsif lower.finite? && upper.finite?
47
+ nbd[n] = 2
48
+ elsif !lower.finite? && upper.finite?
49
+ nbd[n] = 3
50
+ end
51
+ end
52
+ end
53
+
54
+ min_l_bfgs_b(fnc, x_init, jcb, args, l, u, nbd, maxcor, factr, pgtol, maxiter, verbose)
55
+ end
56
+
57
+ # @!visibility private
58
+ def fnc(fnc, x, args)
59
+ if args.is_a?(Hash)
60
+ fnc.call(x, **args)
61
+ elsif args.is_a?(Array)
62
+ fnc.call(x, *args)
63
+ elsif args.nil?
64
+ fnc.call(x)
65
+ else
66
+ fnc.call(x, args)
67
+ end
68
+ end
69
+
70
+ # @!visibility private
71
+ def jcb(jcb, x, args)
72
+ if args.is_a?(Hash)
73
+ jcb.call(x, **args)
74
+ elsif args.is_a?(Array)
75
+ jcb.call(x, *args)
76
+ elsif args.nil?
77
+ jcb.call(x)
78
+ else
79
+ jcb.call(x, args)
80
+ end
81
+ end
82
+
83
+ private_class_method :fnc, :jcb, :min_l_bfgs_b
84
+ end