lbfgsb 0.4.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 209395124eb39ffdf43a87f346023646fa5367a66f382378542dabdc15668cdf
4
- data.tar.gz: 9684de7283ba7ff88d6c8408dead7c8468f11e33b4a8010b1c837a2efeb635aa
3
+ metadata.gz: b8b981810814f144065eb51dadf5c310ce4eaa5080e1cb4092189dbe916387bf
4
+ data.tar.gz: 1ba3ff6d1cfe6fe0e0a707963b39554d7ad2c1e8be8829d8eaf1918ffd743adf
5
5
  SHA512:
6
- metadata.gz: 89cf143fe2b33ab916200814aed666bbcbe2de19852955bcb672ff065939657d2d82dde2e12b14d8cf79aa73d40aebba68d335dd49b68a302af311d7d45f3b3f
7
- data.tar.gz: bca9b1a012e020669b1b491ff54a40230da72f70efbf8540945239b487d4d6b08fd2a7f3a11600736b40bc6a25f661ed040a0e8077f80273e17a484000a1c045
6
+ metadata.gz: 778a041c3072451e86dccd5d75850540fc2503d49f14e1a4c11db9c20f05f0d427627f2f17c5931fe90dba68ba3ab5760b4f59a811f5af19eb5f0ce12ab0891c
7
+ data.tar.gz: 01d735e9f03a3bc4615cf5b471a2c88bc210663b7d268edf0898c5936e50a2b636cfd8ee6e1664c6d225c6872aa7108bd00aece439629a4d5c691d90bd6e7913
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## 0.5.1
2
+ - Refactor codes and configs with RuboCop.
3
+
4
+ ## 0.5.0
5
+ - Add build option to select FORTRAN integer bit size.
6
+
7
+ ```
8
+ $ gem install lbfgsb -- --with-use-int64
9
+ ```
10
+
11
+ - Add build option to use any blas library.
12
+
13
+ ```
14
+ $ gem install lbfgsb -- --with-blas-dir=/opt/local/openblas/lib --with-blas-lib=openblas
15
+ ```
16
+
17
+ - Change to use 32-bit integer for FORTRAN integer in internal functions by default.
18
+ - Introduce conventional commits.
19
+
20
+ ## 0.4.1
21
+ - Remove dependent gem's type declaration file from installation files.
22
+
1
23
  ## 0.4.0
2
24
  - Add type declaration file: sig/lbfgsb.rbs
3
25
 
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2020-2021 Atsushi Tatsuma
1
+ Copyright (c) 2020-2022 Atsushi Tatsuma
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without
data/README.md CHANGED
@@ -3,9 +3,9 @@
3
3
  [![Build Status](https://github.com/yoshoku/lbfgsb.rb/workflows/build/badge.svg)](https://github.com/yoshoku/lbfgsb.rb/actions?query=workflow%3Abuild)
4
4
  [![Gem Version](https://badge.fury.io/rb/lbfgsb.svg)](https://badge.fury.io/rb/lbfgsb)
5
5
  [![BSD 3-Clause License](https://img.shields.io/badge/License-BSD%203--Clause-orange.svg)](https://github.com/yoshoku/suika/blob/main/LICENSE.txt)
6
- [![Documentation](http://img.shields.io/badge/api-reference-blue.svg)](https://yoshoku.github.io/lbfgsb.rb/doc/)
6
+ [![Documentation](https://img.shields.io/badge/api-reference-blue.svg)](https://yoshoku.github.io/lbfgsb.rb/doc/)
7
7
 
8
- Lbfgsb.rb is a Ruby binding for [L-BFGS-B](http://users.iems.northwestern.edu/~nocedal/lbfgsb.html)
8
+ Lbfgsb.rb is a Ruby binding for [L-BFGS-B](https://users.iems.northwestern.edu/~nocedal/lbfgsb.html)
9
9
  that is a limited-memory algorithm for solving large nonlinear optimization problems
10
10
  subject to simple bounds on the variables.
11
11
  L-BFGS-B is written in FORTRAN. Author converted the codes into C-lang
@@ -27,6 +27,20 @@ Or install it yourself as:
27
27
 
28
28
  $ gem install lbfgsb
29
29
 
30
+ Notes: lbfgsb.rb uses 32-bit integer for the integer type in its native code.
31
+ If you want to use 64-bit integer, give the installation option as below:
32
+
33
+ ```
34
+ $ gem install lbfgsb -- --with-use-int64
35
+ ```
36
+
37
+ In adition, if you want to use an external BLAS library for linear algebra on LBFGSB optimization,
38
+ give the directory and library in the installation options as follows:
39
+
40
+ ```
41
+ $ gem install lbfgsb -- --with-blas-dir=/opt/local/openblas/lib --with-blas-lib=openblas
42
+ ```
43
+
30
44
  ## Usage
31
45
  Example 1. Logistic Regression
32
46
 
@@ -1,6 +1,8 @@
1
1
  require 'mkmf'
2
2
  require 'numo/narray'
3
3
 
4
+ $defs << '-DUSE_INT64' if with_config('use-int64', false)
5
+
4
6
  $LOAD_PATH.each do |lp|
5
7
  if File.exist?(File.join(lp, 'numo/numo/narray.h'))
6
8
  $INCFLAGS = "-I#{lp}/numo #{$INCFLAGS}"
@@ -26,10 +28,17 @@ if RUBY_PLATFORM =~ /mswin|cygwin|mingw/
26
28
  end
27
29
  end
28
30
 
29
- $srcs = Dir.glob("#{$srcdir}/*.c").map { |path| File.basename(path) }
30
- $srcs.concat(%w[blas.c linpack.c lbfgsb.c])
31
+ $srcs = Dir.glob("#{$srcdir}/**/*.c").map { |path| File.basename(path) }
32
+
33
+ blas_dir = with_config('blas-dir')
34
+ $LDFLAGS = "-L#{blas_dir} #{$LDFLAGS}" unless blas_dir.nil?
35
+
36
+ blas_lib = with_config('blas-lib')
37
+ unless blas_lib.nil?
38
+ abort "#{blas_lib} not found." unless have_library(blas_lib)
39
+ $srcs.delete('blas.c')
40
+ end
31
41
 
32
- $INCFLAGS << " -I$(srcdir)/src"
33
42
  $VPATH << "$(srcdir)/src"
34
43
 
35
44
  create_makefile('lbfgsb/lbfgsbext')
@@ -4,31 +4,43 @@ VALUE rb_mLbfgsb;
4
4
 
5
5
  static VALUE lbfgsb_min_l_bfgs_b(VALUE self, VALUE fnc, VALUE x_val, VALUE jcb, VALUE args, VALUE l_val, VALUE u_val,
6
6
  VALUE nbd_val, VALUE maxcor, VALUE ftol, VALUE gtol, VALUE maxiter, VALUE disp) {
7
- long n_iter;
8
- long n_fev;
9
- long n_jev;
10
- long max_iter = NUM2LONG(maxiter);
7
+ F77_int n_iter;
8
+ F77_int n_fev;
9
+ F77_int n_jev;
10
+ #ifdef USE_INT64
11
+ F77_int max_iter = NUM2LONG(maxiter);
12
+ #else
13
+ F77_int max_iter = NUM2INT(maxiter);
14
+ #endif
11
15
  narray_t* x_nary;
12
16
  narray_t* l_nary;
13
17
  narray_t* u_nary;
14
18
  narray_t* nbd_nary;
15
- long n;
16
- long m = NUM2LONG(maxcor);
19
+ F77_int n;
20
+ #ifdef USE_INT64
21
+ F77_int m = NUM2LONG(maxcor);
22
+ #else
23
+ F77_int m = NUM2INT(maxcor);
24
+ #endif
17
25
  double* x_ptr;
18
26
  double* l_ptr;
19
27
  double* u_ptr;
20
- long* nbd_ptr;
28
+ F77_int* nbd_ptr;
21
29
  double f;
22
30
  double* g;
23
31
  double factr = NUM2DBL(ftol);
24
32
  double pgtol = NUM2DBL(gtol);
25
33
  double* wa;
26
- long* iwa;
34
+ F77_int* iwa;
27
35
  char task[60];
28
- long iprint = NIL_P(disp) ? -1 : NUM2LONG(disp);
36
+ #ifdef USE_INT64
37
+ F77_int iprint = NIL_P(disp) ? -1 : NUM2LONG(disp);
38
+ #else
39
+ F77_int iprint = NIL_P(disp) ? -1 : NUM2INT(disp);
40
+ #endif
29
41
  char csave[60];
30
- long lsave[4];
31
- long isave[44];
42
+ F77_int lsave[4];
43
+ F77_int isave[44];
32
44
  double dsave[29];
33
45
  VALUE g_val;
34
46
  VALUE fg_arr;
@@ -39,7 +51,7 @@ static VALUE lbfgsb_min_l_bfgs_b(VALUE self, VALUE fnc, VALUE x_val, VALUE jcb,
39
51
  rb_raise(rb_eArgError, "x must be a 1-D array.");
40
52
  return Qnil;
41
53
  }
42
- n = (long)NA_SIZE(x_nary);
54
+ n = (F77_int)NA_SIZE(x_nary);
43
55
  if (CLASS_OF(x_val) != numo_cDFloat) {
44
56
  x_val = rb_funcall(numo_cDFloat, rb_intern("cast"), 1, x_val);
45
57
  }
@@ -52,7 +64,7 @@ static VALUE lbfgsb_min_l_bfgs_b(VALUE self, VALUE fnc, VALUE x_val, VALUE jcb,
52
64
  rb_raise(rb_eArgError, "l must be a 1-D array.");
53
65
  return Qnil;
54
66
  }
55
- if ((long)NA_SIZE(l_nary) != n) {
67
+ if ((F77_int)NA_SIZE(l_nary) != n) {
56
68
  rb_raise(rb_eArgError, "The size of l must be equal to that of x.");
57
69
  return Qnil;
58
70
  }
@@ -68,7 +80,7 @@ static VALUE lbfgsb_min_l_bfgs_b(VALUE self, VALUE fnc, VALUE x_val, VALUE jcb,
68
80
  rb_raise(rb_eArgError, "u must be a 1-D array.");
69
81
  return Qnil;
70
82
  }
71
- if ((long)NA_SIZE(u_nary) != n) {
83
+ if ((F77_int)NA_SIZE(u_nary) != n) {
72
84
  rb_raise(rb_eArgError, "The size of u must be equal to that of x.");
73
85
  return Qnil;
74
86
  }
@@ -84,13 +96,19 @@ static VALUE lbfgsb_min_l_bfgs_b(VALUE self, VALUE fnc, VALUE x_val, VALUE jcb,
84
96
  rb_raise(rb_eArgError, "nbd must be a 1-D array.");
85
97
  return Qnil;
86
98
  }
87
- if ((long)NA_SIZE(nbd_nary) != n) {
99
+ if ((F77_int)NA_SIZE(nbd_nary) != n) {
88
100
  rb_raise(rb_eArgError, "The size of nbd must be equal to that of x.");
89
101
  return Qnil;
90
102
  }
103
+ #ifdef USE_INT64
91
104
  if (CLASS_OF(nbd_val) != numo_cInt64) {
92
105
  nbd_val = rb_funcall(numo_cInt64, rb_intern("cast"), 1, nbd_val);
93
106
  }
107
+ #else
108
+ if (CLASS_OF(nbd_val) != numo_cInt32) {
109
+ nbd_val = rb_funcall(numo_cInt32, rb_intern("cast"), 1, nbd_val);
110
+ }
111
+ #endif
94
112
  if (!RTEST(nary_check_contiguous(nbd_val))) {
95
113
  nbd_val = nary_dup(nbd_val);
96
114
  }
@@ -98,10 +116,10 @@ static VALUE lbfgsb_min_l_bfgs_b(VALUE self, VALUE fnc, VALUE x_val, VALUE jcb,
98
116
  x_ptr = (double*)na_get_pointer_for_read_write(x_val);
99
117
  l_ptr = (double*)na_get_pointer_for_read(l_val);
100
118
  u_ptr = (double*)na_get_pointer_for_read(u_val);
101
- nbd_ptr = (long*)na_get_pointer_for_read(nbd_val);
119
+ nbd_ptr = (F77_int*)na_get_pointer_for_read(nbd_val);
102
120
  g = ALLOC_N(double, n);
103
121
  wa = ALLOC_N(double, (2 * m + 5) * n + 12 * m * m + 12 * m);
104
- iwa = ALLOC_N(long, 3 * n);
122
+ iwa = ALLOC_N(F77_int, 3 * n);
105
123
 
106
124
  g_val = Qnil;
107
125
  f = 0.0;
@@ -145,9 +163,15 @@ static VALUE lbfgsb_min_l_bfgs_b(VALUE self, VALUE fnc, VALUE x_val, VALUE jcb,
145
163
  rb_hash_aset(ret, ID2SYM(rb_intern("x")), x_val);
146
164
  rb_hash_aset(ret, ID2SYM(rb_intern("fnc")), DBL2NUM(f));
147
165
  rb_hash_aset(ret, ID2SYM(rb_intern("jcb")), g_val);
166
+ #ifdef USE_INT64
148
167
  rb_hash_aset(ret, ID2SYM(rb_intern("n_iter")), LONG2NUM(n_iter));
149
168
  rb_hash_aset(ret, ID2SYM(rb_intern("n_fev")), LONG2NUM(n_fev));
150
169
  rb_hash_aset(ret, ID2SYM(rb_intern("n_jev")), LONG2NUM(n_jev));
170
+ #else
171
+ rb_hash_aset(ret, ID2SYM(rb_intern("n_iter")), INT2NUM(n_iter));
172
+ rb_hash_aset(ret, ID2SYM(rb_intern("n_fev")), INT2NUM(n_fev));
173
+ rb_hash_aset(ret, ID2SYM(rb_intern("n_jev")), INT2NUM(n_jev));
174
+ #endif
151
175
  rb_hash_aset(ret, ID2SYM(rb_intern("success")), strncmp(task, "CONV", 4) == 0 ? Qtrue : Qfalse);
152
176
 
153
177
  RB_GC_GUARD(x_val);
@@ -162,6 +186,13 @@ void Init_lbfgsbext(void) {
162
186
  rb_mLbfgsb = rb_define_module("Lbfgsb");
163
187
  /* The value of double epsilon used in the native extension. */
164
188
  rb_define_const(rb_mLbfgsb, "DBL_EPSILON", DBL2NUM(DBL_EPSILON));
189
+ #ifdef USE_INT64
190
+ /* The bit size of fortran integer. */
191
+ rb_define_const(rb_mLbfgsb, "SZ_F77_INTEGER", INT2NUM(64));
192
+ #else
193
+ /* The bit size of fortran integer. */
194
+ rb_define_const(rb_mLbfgsb, "SZ_F77_INTEGER", INT2NUM(32));
195
+ #endif
165
196
  /* @!visibility private */
166
197
  rb_define_module_function(rb_mLbfgsb, "min_l_bfgs_b", lbfgsb_min_l_bfgs_b, 12);
167
198
  }
@@ -9,6 +9,6 @@
9
9
  #include <numo/narray.h>
10
10
  #include <numo/template.h>
11
11
 
12
- #include <lbfgsb.h>
12
+ #include "src/lbfgsb.h"
13
13
 
14
14
  #endif /* LBFGSB_RB_H */
@@ -5,9 +5,9 @@
5
5
  */
6
6
  #include "blas.h"
7
7
 
8
- int lbfgsb_rb_daxpy_(long* n, double* da, double* dx, long* incx, double* dy, long* incy) {
9
- long i__1;
10
- static long i__, m, ix, iy, mp1;
8
+ void daxpy_(F77_int* n, double* da, double* dx, F77_int* incx, double* dy, F77_int* incy) {
9
+ F77_int i__1;
10
+ static F77_int i__, m, ix, iy, mp1;
11
11
 
12
12
  --dy;
13
13
  --dx;
@@ -16,10 +16,10 @@ int lbfgsb_rb_daxpy_(long* n, double* da, double* dx, long* incx, double* dy, lo
16
16
  /* uses unrolled loops for increments equal to one. */
17
17
  /* jack dongarra, linpack, 3/11/78. */
18
18
  if (*n <= 0) {
19
- return 0;
19
+ return;
20
20
  }
21
21
  if (*da == 0.) {
22
- return 0;
22
+ return;
23
23
  }
24
24
  if (*incx == 1 && *incy == 1) {
25
25
  goto L20;
@@ -41,7 +41,7 @@ int lbfgsb_rb_daxpy_(long* n, double* da, double* dx, long* incx, double* dy, lo
41
41
  ix += *incx;
42
42
  iy += *incy;
43
43
  }
44
- return 0;
44
+ return;
45
45
 
46
46
  /* code for both increments equal to 1 */
47
47
  /* clean-up loop */
@@ -55,7 +55,7 @@ L20:
55
55
  dy[i__] += *da * dx[i__];
56
56
  }
57
57
  if (*n < 4) {
58
- return 0;
58
+ return;
59
59
  }
60
60
  L40:
61
61
  mp1 = m + 1;
@@ -66,12 +66,12 @@ L40:
66
66
  dy[i__ + 2] += *da * dx[i__ + 2];
67
67
  dy[i__ + 3] += *da * dx[i__ + 3];
68
68
  }
69
- return 0;
69
+ return;
70
70
  }
71
71
 
72
- int lbfgsb_rb_dcopy_(long* n, double* dx, long* incx, double* dy, long* incy) {
73
- long i__1;
74
- static long i__, m, ix, iy, mp1;
72
+ void dcopy_(F77_int* n, double* dx, F77_int* incx, double* dy, F77_int* incy) {
73
+ F77_int i__1;
74
+ static F77_int i__, m, ix, iy, mp1;
75
75
 
76
76
  --dy;
77
77
  --dx;
@@ -80,7 +80,7 @@ int lbfgsb_rb_dcopy_(long* n, double* dx, long* incx, double* dy, long* incy) {
80
80
  /* uses unrolled loops for increments equal to one. */
81
81
  /* jack dongarra, linpack, 3/11/78. */
82
82
  if (*n <= 0) {
83
- return 0;
83
+ return;
84
84
  }
85
85
  if (*incx == 1 && *incy == 1) {
86
86
  goto L20;
@@ -102,7 +102,7 @@ int lbfgsb_rb_dcopy_(long* n, double* dx, long* incx, double* dy, long* incy) {
102
102
  ix += *incx;
103
103
  iy += *incy;
104
104
  }
105
- return 0;
105
+ return;
106
106
 
107
107
  /* code for both increments equal to 1 */
108
108
  /* clean-up loop */
@@ -116,7 +116,7 @@ L20:
116
116
  dy[i__] = dx[i__];
117
117
  }
118
118
  if (*n < 7) {
119
- return 0;
119
+ return;
120
120
  }
121
121
  L40:
122
122
  mp1 = m + 1;
@@ -130,13 +130,13 @@ L40:
130
130
  dy[i__ + 5] = dx[i__ + 5];
131
131
  dy[i__ + 6] = dx[i__ + 6];
132
132
  }
133
- return 0;
133
+ return;
134
134
  }
135
135
 
136
- double lbfgsb_rb_ddot_(long* n, double* dx, long* incx, double* dy, long* incy) {
137
- long i__1;
136
+ double ddot_(F77_int* n, double* dx, F77_int* incx, double* dy, F77_int* incy) {
137
+ F77_int i__1;
138
138
  double ret_val;
139
- static long i__, m, ix, iy, mp1;
139
+ static F77_int i__, m, ix, iy, mp1;
140
140
  static double dtemp;
141
141
 
142
142
  --dy;
@@ -199,9 +199,9 @@ L60:
199
199
  return ret_val;
200
200
  }
201
201
 
202
- int lbfgsb_rb_dscal_(long* n, double* da, double* dx, long* incx) {
203
- long i__1, i__2;
204
- static long i__, m, mp1, nincx;
202
+ void dscal_(F77_int* n, double* da, double* dx, F77_int* incx) {
203
+ F77_int i__1, i__2;
204
+ static F77_int i__, m, mp1, nincx;
205
205
 
206
206
  --dx;
207
207
 
@@ -210,7 +210,7 @@ int lbfgsb_rb_dscal_(long* n, double* da, double* dx, long* incx) {
210
210
  /* jack dongarra, linpack, 3/11/78. */
211
211
  /* modified 3/93 to return if incx .le. 0. */
212
212
  if (*n <= 0 || *incx <= 0) {
213
- return 0;
213
+ return;
214
214
  }
215
215
  if (*incx == 1) {
216
216
  goto L20;
@@ -223,7 +223,7 @@ int lbfgsb_rb_dscal_(long* n, double* da, double* dx, long* incx) {
223
223
  for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) {
224
224
  dx[i__] = *da * dx[i__];
225
225
  }
226
- return 0;
226
+ return;
227
227
 
228
228
  /* code for increment equal to 1 */
229
229
  /* clean-up loop */
@@ -237,7 +237,7 @@ L20:
237
237
  dx[i__] = *da * dx[i__];
238
238
  }
239
239
  if (*n < 5) {
240
- return 0;
240
+ return;
241
241
  }
242
242
  L40:
243
243
  mp1 = m + 1;
@@ -249,5 +249,5 @@ L40:
249
249
  dx[i__ + 3] = *da * dx[i__ + 3];
250
250
  dx[i__ + 4] = *da * dx[i__ + 4];
251
251
  }
252
- return 0;
252
+ return;
253
253
  }
@@ -1,11 +1,11 @@
1
1
  #ifndef LBFGSB_RB_BLAS_H_
2
2
  #define LBFGSB_RB_BLAS_H_
3
3
 
4
- #include <math.h>
4
+ #include "common.h"
5
5
 
6
- extern int lbfgsb_rb_daxpy_(long* n, double* da, double* dx, long* incx, double* dy, long* incy);
7
- extern int lbfgsb_rb_dcopy_(long* n, double* dx, long* incx, double* dy, long* incy);
8
- extern double lbfgsb_rb_ddot_(long* n, double* dx, long* incx, double* dy, long* incy);
9
- extern int lbfgsb_rb_dscal_(long* n, double* da, double* dx, long* incx);
6
+ extern void daxpy_(F77_int* n, double* da, double* dx, F77_int* incx, double* dy, F77_int* incy);
7
+ extern void dcopy_(F77_int* n, double* dx, F77_int* incx, double* dy, F77_int* incy);
8
+ extern double ddot_(F77_int* n, double* dx, F77_int* incx, double* dy, F77_int* incy);
9
+ extern void dscal_(F77_int* n, double* da, double* dx, F77_int* incx);
10
10
 
11
11
  #endif /* LBFGSB_RB_BLAS_H_ */
@@ -0,0 +1,16 @@
1
+ #ifndef LBFGSB_RB_COMMON_H_
2
+ #define LBFGSB_RB_COMMON_H_
3
+
4
+ #include <stdint.h>
5
+ #include <inttypes.h>
6
+ #include <math.h>
7
+
8
+ #ifdef USE_INT64
9
+ typedef int64_t F77_int;
10
+ #define PRIdF77INT PRId64
11
+ #else
12
+ typedef int32_t F77_int;
13
+ #define PRIdF77INT PRId32
14
+ #endif
15
+
16
+ #endif /* LBFGSB_RB_COMMON_H_ */