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