lbfgsb 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,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