lbfgsb 0.4.0 → 0.5.1

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.
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_ */