osqp 0.3.0 → 0.4.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: b6ed92bcdae0ff5291f26741fc77be7da17b2dc1e4bb6680df7c20516f6b894e
4
- data.tar.gz: 7f66c0c4d72a6bb77abb7d3cf4119d79117c92079d7b4dde460d2d952277aed1
3
+ metadata.gz: 1e146965f2438ae0573b8c96e3db75ea93698909fe2d6d03b8c03c0943d37b11
4
+ data.tar.gz: 5d626037990f92d81be5b8b555a19f03b175e0bf77de6706cec883cd1a1b35d6
5
5
  SHA512:
6
- metadata.gz: e16b34d395a64988f04c2779d67dfd164162940e92cbd857ae324aa694ee04e05162fd8cb9532a2a7b828d598814bff5fd4cce8601a8b29e3f69913d530085b9
7
- data.tar.gz: f8b0dfb4a6657d7398bd3f366c8368bc82233e611890f19e603e21b45a566cd9a7b12e07cb894a669872eab28948d79df919aa973f686d980a94889f4cbdef1e
6
+ metadata.gz: 6e02b4c79b5b04e01e05c15c267300e06a69449fa262f82a69c0c3c8ccfae5f17e702d52ef6f5189f0344d4132bda3ff06a293294f122620a55417bf030d2d1c
7
+ data.tar.gz: ef9a8790844d94b93b92b7687ea27e70f1473dd2eac4c4a5ab14720cac395f88a7ca177a9450c521f2ba90f9900a48b83e6a65a57011359aba18e16647326c53
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 0.4.1 (2025-04-26)
2
+
3
+ - Fixed memory leaks
4
+ - Fixed error messages for OSQP 1.0.0
5
+
6
+ ## 0.4.0 (2025-04-01)
7
+
8
+ - Updated OSQP to 1.0.0
9
+ - Dropped support for Ruby < 3.2
10
+
1
11
  ## 0.3.0 (2024-10-23)
2
12
 
3
13
  - Dropped support for Ruby < 3.1
data/NOTICE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2019-2020 Andrew Kane
1
+ Copyright (c) 2019-2025 Andrew Kane
2
2
 
3
3
  OSQP
4
4
  Copyright (c) 2019 Bartolomeo Stellato, Goran Banjac, Paul Goulart, Stephen Boyd
data/lib/osqp/ffi.rb CHANGED
@@ -10,139 +10,122 @@ module OSQP
10
10
  raise e
11
11
  end
12
12
 
13
- typealias "c_float", "double"
14
- typealias "c_int", "long long"
13
+ typealias "OSQPFloat", "double"
14
+ typealias "OSQPInt", "long long"
15
15
  typealias "enum", "int"
16
16
 
17
17
  OSQP_INFTY = 1e30
18
18
 
19
- Data = struct [
20
- "c_int n",
21
- "c_int m",
22
- "csc *p",
23
- "csc *a",
24
- "c_float *q",
25
- "c_float *l",
26
- "c_float *u"
27
- ]
28
-
29
19
  Settings = struct [
30
- "c_float rho",
31
- "c_float sigma",
32
- "c_int scaling",
33
- "c_int adaptive_rho",
34
- "c_int adaptive_rho_interval",
35
- "c_float adaptive_rho_tolerance",
36
- "c_float adaptive_rho_fraction",
37
- "c_int max_iter",
38
- "c_float eps_abs",
39
- "c_float eps_rel",
40
- "c_float eps_prim_inf",
41
- "c_float eps_dual_inf",
42
- "c_float alpha",
43
- "enum linsys_solver_type linsys_solver",
44
- "c_float delta",
45
- "c_int polish",
46
- "c_int polish_refine_iter",
47
- "c_int verbose",
48
- "c_int scaled_termination",
49
- "c_int check_termination",
50
- "c_int warm_start",
51
- "c_float time_limit"
20
+ # linear algebra settings
21
+ "OSQPInt device",
22
+ "enum osqp_linsys_solver_type linsys_solver",
23
+
24
+ # control settings
25
+ "OSQPInt allocate_solution",
26
+ "OSQPInt verbose",
27
+ "OSQPInt profiler_level",
28
+ "OSQPInt warm_starting",
29
+ "OSQPInt scaling",
30
+ "OSQPInt polishing",
31
+
32
+ # ADMM parameters
33
+ "OSQPFloat rho",
34
+ "OSQPInt rho_is_vec",
35
+ "OSQPFloat sigma",
36
+ "OSQPFloat alpha",
37
+
38
+ # CG settings
39
+ "OSQPInt cg_max_iter",
40
+ "OSQPInt cg_tol_reduction",
41
+ "OSQPFloat cg_tol_fraction",
42
+ "enum osqp_precond_type cg_precond",
43
+
44
+ # adaptive rho logic
45
+ "OSQPInt adaptive_rho",
46
+ "OSQPInt adaptive_rho_interval",
47
+ "OSQPFloat adaptive_rho_fraction",
48
+ "OSQPFloat adaptive_rho_tolerance",
49
+
50
+ # termination parameters
51
+ "OSQPInt max_iter",
52
+ "OSQPFloat eps_abs",
53
+ "OSQPFloat eps_rel",
54
+ "OSQPFloat eps_prim_inf",
55
+ "OSQPFloat eps_dual_inf",
56
+ "OSQPInt scaled_termination",
57
+ "OSQPInt check_termination",
58
+ "OSQPInt check_dualgap",
59
+ "OSQPFloat time_limit",
60
+
61
+ # polishing parameters
62
+ "OSQPFloat delta",
63
+ "OSQPInt polish_refine_iter"
52
64
  ]
53
65
 
54
66
  Info = struct [
55
- "c_int iter",
67
+ # solver status
56
68
  "char status[32]",
57
- "c_int status_val",
58
- "c_int status_polish",
59
- "c_float obj_val",
60
- "c_float pri_res",
61
- "c_float dua_res",
62
- "c_float setup_time",
63
- "c_float solve_time",
64
- "c_float update_time",
65
- "c_float polish_time",
66
- "c_float run_time",
67
- "c_int rho_updates",
68
- "c_float rho_estimate"
69
+ "OSQPInt status_val",
70
+ "OSQPInt status_polish",
71
+
72
+ # solution quality
73
+ "OSQPFloat obj_val",
74
+ "OSQPFloat dual_obj_val",
75
+ "OSQPFloat prim_res",
76
+ "OSQPFloat dual_res",
77
+ "OSQPFloat duality_gap",
78
+
79
+ # algorithm information
80
+ "OSQPInt iter",
81
+ "OSQPInt rho_updates",
82
+ "OSQPFloat rho_estimate",
83
+
84
+ # timing information
85
+ "OSQPFloat setup_time",
86
+ "OSQPFloat solve_time",
87
+ "OSQPFloat update_time",
88
+ "OSQPFloat polish_time",
89
+ "OSQPFloat run_time",
90
+
91
+ # convergence information
92
+ "OSQPFloat primdual_int",
93
+ "OSQPFloat rel_kkt_error"
69
94
  ]
70
95
 
71
96
  Solution = struct [
72
- "c_float *x",
73
- "c_float *y"
97
+ "OSQPFloat *x",
98
+ "OSQPFloat *y",
99
+ "OSQPFloat *prim_inf_cert",
100
+ "OSQPFloat *dual_inf_cert"
74
101
  ]
75
102
 
76
- Workspace = struct [
77
- "OSQPData *data",
78
- "LinSysSolver *linsys_solver",
79
- "OSQPPolish *pol",
80
- "c_float *rho_vec",
81
- "c_float *rho_inv_vec",
82
- "c_int *constr_type",
83
- "c_float *x",
84
- "c_float *y",
85
- "c_float *z",
86
- "c_float *xz_tilde",
87
- "c_float *x_prev",
88
- "c_float *z_prev",
89
- "c_float *Ax",
90
- "c_float *Px",
91
- "c_float *Aty",
92
- "c_float *delta_y",
93
- "c_float *Atdelta_y",
94
- "c_float *delta_x",
95
- "c_float *Pdelta_x",
96
- "c_float *Adelta_x",
97
- "c_float *D_temp",
98
- "c_float *D_temp_A",
99
- "c_float *E_temp",
100
- "OSQPSettings *settings",
101
- "OSQPScaling *scaling",
102
- "OSQPSolution *solution",
103
- "OSQPInfo *info",
104
- "OSQPTimer *timer",
105
- "c_int first_run",
106
- "c_int clear_update_time",
107
- "c_int rho_update_from_solve",
108
- "c_int summary_printed"
103
+ Solver = struct [
104
+ "OSQPSettings* settings",
105
+ "OSQPSolution* solution",
106
+ "OSQPInfo* info",
107
+ "OSQPWorkspace* work"
109
108
  ]
110
109
 
111
- # cs.h
112
- extern "csc* csc_matrix(c_int m, c_int n, c_int nzmax, c_float *x, c_int *i, c_int *p)"
113
-
114
- # osqp.h
115
- extern "void osqp_set_default_settings(OSQPSettings *settings)"
116
- extern "c_int osqp_setup(OSQPWorkspace** workp, OSQPData* data, OSQPSettings* settings)"
117
- extern "c_int osqp_solve(OSQPWorkspace *work)"
118
- extern "c_int osqp_cleanup(OSQPWorkspace *work)"
119
- extern "c_int osqp_update_lin_cost(OSQPWorkspace *work, c_float *q_new)"
120
- extern "c_int osqp_update_bounds(OSQPWorkspace *work, c_float *l_new, c_float *u_new)"
121
- extern "c_int osqp_update_lower_bound(OSQPWorkspace *work, c_float *l_new)"
122
- extern "c_int osqp_update_upper_bound(OSQPWorkspace *work, c_float *u_new)"
123
- extern "c_int osqp_warm_start(OSQPWorkspace *work, c_float *x, c_float *y)"
124
- extern "c_int osqp_warm_start_x(OSQPWorkspace *work, c_float *x)"
125
- extern "c_int osqp_warm_start_y(OSQPWorkspace *work, c_float *y)"
126
- extern "c_int osqp_update_P(OSQPWorkspace *work, c_float *Px_new, c_int *Px_new_idx, c_int P_new_n)"
127
- extern "c_int osqp_update_A(OSQPWorkspace *work, c_float *Ax_new, c_int *Ax_new_idx, c_int A_new_n)"
128
- extern "c_int osqp_update_P_A(OSQPWorkspace *work, c_float *Px_new, c_int *Px_new_idx, c_int P_new_n, c_float *Ax_new, c_int *Ax_new_idx, c_int A_new_n)"
129
- extern "c_int osqp_update_rho(OSQPWorkspace *work, c_float rho_new)"
130
- extern "c_int osqp_update_max_iter(OSQPWorkspace *work, c_int max_iter_new)"
131
- extern "c_int osqp_update_eps_abs(OSQPWorkspace *work, c_float eps_abs_new)"
132
- extern "c_int osqp_update_eps_rel(OSQPWorkspace *work, c_float eps_rel_new)"
133
- extern "c_int osqp_update_eps_prim_inf(OSQPWorkspace *work, c_float eps_prim_inf_new)"
134
- extern "c_int osqp_update_eps_dual_inf(OSQPWorkspace *work, c_float eps_dual_inf_new)"
135
- extern "c_int osqp_update_alpha(OSQPWorkspace *work, c_float alpha_new)"
136
- extern "c_int osqp_update_warm_start(OSQPWorkspace *work, c_int warm_start_new)"
137
- extern "c_int osqp_update_scaled_termination(OSQPWorkspace *work, c_int scaled_termination_new)"
138
- extern "c_int osqp_update_check_termination(OSQPWorkspace *work, c_int check_termination_new)"
139
- extern "c_int osqp_update_delta(OSQPWorkspace *work, c_float delta_new)"
140
- extern "c_int osqp_update_polish(OSQPWorkspace *work, c_int polish_new)"
141
- extern "c_int osqp_update_polish_refine_iter(OSQPWorkspace *work, c_int polish_refine_iter_new)"
142
- extern "c_int osqp_update_verbose(OSQPWorkspace *work, c_int verbose_new)"
143
- extern "c_int osqp_update_time_limit(OSQPWorkspace *work, c_float time_limit_new)"
144
-
145
- # util.h
110
+ # https://github.com/osqp/osqp/blob/master/include/public/osqp_api_functions.h
111
+
112
+ # CSC matrix manipulation
113
+ extern "OSQPCscMatrix* OSQPCscMatrix_new(OSQPInt m, OSQPInt n, OSQPInt nzmax, OSQPFloat* x, OSQPInt* i, OSQPInt* p)"
114
+ extern "void OSQPCscMatrix_free(OSQPCscMatrix* mat)"
115
+
116
+ # main solver API
146
117
  extern "const char* osqp_version(void)"
118
+ extern "const char* osqp_error_message(OSQPInt error_flag)"
119
+ extern "void osqp_get_dimensions(OSQPSolver* solver, OSQPInt* m, OSQPInt* n)"
120
+ extern "OSQPInt osqp_setup(OSQPSolver** solverp, OSQPCscMatrix* P, OSQPFloat* q, OSQPCscMatrix* A, OSQPFloat* l, OSQPFloat* u, OSQPInt m, OSQPInt n, OSQPSettings* settings)"
121
+ extern "OSQPInt osqp_solve(OSQPSolver* solver)"
122
+ extern "OSQPInt osqp_cleanup(OSQPSolver* solver)"
123
+
124
+ # sublevel API
125
+ extern "OSQPInt osqp_warm_start(OSQPSolver* solver, OSQPFloat* x, OSQPFloat* y)"
126
+ extern "void osqp_cold_start(OSQPSolver* solver)"
127
+
128
+ # settings
129
+ extern "void osqp_set_default_settings(OSQPSettings* settings)"
147
130
  end
148
131
  end
data/lib/osqp/solver.rb CHANGED
@@ -16,19 +16,12 @@ module OSQP
16
16
  l = float_array(l)
17
17
  u = float_array(u)
18
18
 
19
- data = FFI::Data.malloc
20
- data.n = a.n
21
- data.m = a.m
22
- data.p = matrix_ptr(p)
23
- data.q = q
24
- data.a = matrix_ptr(a)
25
- data.l = l
26
- data.u = u
27
-
28
19
  # work
29
- work = FFI::Workspace.malloc
30
- check_result FFI.osqp_setup(work.to_ptr.ref, data, set)
31
- @work = work
20
+ work_ptr = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE)
21
+ check_result FFI.osqp_setup(work_ptr, matrix_ptr(p), q, matrix_ptr(a), l, u, a.m, a.n, set)
22
+ work = work_ptr.ptr
23
+ work.free = FFI["osqp_cleanup"]
24
+ @work = FFI::Solver.new(work)
32
25
  end
33
26
 
34
27
  def solve(*args, **settings)
@@ -38,9 +31,9 @@ module OSQP
38
31
 
39
32
  # solution
40
33
  solution = FFI::Solution.new(@work.solution)
41
- data = FFI::Data.new(@work.data)
42
- x = read_float_array(solution.x, data.n)
43
- y = read_float_array(solution.y, data.m)
34
+ m, n = dimensions
35
+ x = read_float_array(solution.x, n)
36
+ y = read_float_array(solution.y, m)
44
37
 
45
38
  # info
46
39
  info = FFI::Info.new(@work.info)
@@ -54,8 +47,8 @@ module OSQP
54
47
  status_val: info.status_val,
55
48
  status_polish: info.status_polish,
56
49
  obj_val: info.obj_val,
57
- pri_res: info.pri_res,
58
- dua_res: info.dua_res,
50
+ pri_res: info.prim_res,
51
+ dua_res: info.dual_res,
59
52
  setup_time: info.setup_time,
60
53
  solve_time: info.solve_time,
61
54
  update_time: info.update_time,
@@ -72,15 +65,7 @@ module OSQP
72
65
  raise Error, "Expected x to be size #{n}, got #{x.size}" if x && x.size != n
73
66
  raise Error, "Expected y to be size #{m}, got #{y.size}" if y && y.size != m
74
67
 
75
- if x && y
76
- check_result FFI.osqp_warm_start(@work, float_array(x), float_array(y))
77
- elsif x
78
- check_result FFI.osqp_warm_start_x(@work, float_array(x))
79
- elsif y
80
- check_result FFI.osqp_warm_start_y(@work, float_array(y))
81
- else
82
- raise Error, "Must set x or y"
83
- end
68
+ check_result FFI.osqp_warm_start(@work, x ? float_array(x) : nil, y ? float_array(y) : nil)
84
69
  end
85
70
 
86
71
  private
@@ -96,15 +81,23 @@ module OSQP
96
81
  when 2
97
82
  "Settings validation error"
98
83
  when 3
99
- "Linear system solver loading error"
100
- when 4
101
84
  "Linear system solver initialization error"
102
- when 5
85
+ when 4
103
86
  "Non-convex problem"
104
- when 6
87
+ when 5
105
88
  "Memory allocation error"
106
- when 7
89
+ when 6
107
90
  "Workspace not initialized"
91
+ when 7
92
+ "Error loading algebra library"
93
+ when 8
94
+ "Error opening file for writing"
95
+ when 9
96
+ "Error validating given code generation defines"
97
+ when 10
98
+ "Solver data not initialized"
99
+ when 11
100
+ "Function not implemented in current algebra"
108
101
  else
109
102
  "Error code #{ret}"
110
103
  end
@@ -133,6 +126,11 @@ module OSQP
133
126
  char_ptr[0, idx].map(&:chr).join
134
127
  end
135
128
 
129
+ def read_int(ptr)
130
+ # OSQP int = long long
131
+ ptr[0, Fiddle::SIZEOF_LONG_LONG].unpack1("q")
132
+ end
133
+
136
134
  def csc_matrix(mtx, upper: false)
137
135
  mtx = Matrix.from_dense(mtx) unless mtx.is_a?(Matrix)
138
136
 
@@ -156,19 +154,23 @@ module OSQP
156
154
  ci = int_array(csc[:index])
157
155
  cp = int_array(csc[:start])
158
156
 
159
- ptr = FFI.csc_matrix(mtx.m, mtx.n, nnz, cx, ci, cp)
157
+ ptr = FFI.OSQPCscMatrix_new(mtx.m, mtx.n, nnz, cx, ci, cp)
158
+ ptr.free = FFI["OSQPCscMatrix_free"]
160
159
  # save refs
161
160
  ptr.instance_variable_set(:@osqp_refs, [cx, ci, cp])
162
161
  ptr
163
162
  end
164
163
 
165
164
  def dimensions
166
- data = FFI::Data.new(@work.data)
167
- [data.m, data.n]
165
+ # OSQP int = long long
166
+ m = Fiddle::Pointer.malloc(Fiddle::SIZEOF_LONG_LONG, Fiddle::RUBY_FREE)
167
+ n = Fiddle::Pointer.malloc(Fiddle::SIZEOF_LONG_LONG, Fiddle::RUBY_FREE)
168
+ FFI.osqp_get_dimensions(@work, m, n)
169
+ [read_int(m), read_int(n)]
168
170
  end
169
171
 
170
172
  def create_settings(settings)
171
- set = FFI::Settings.malloc
173
+ set = FFI::Settings.malloc(Fiddle::RUBY_FREE)
172
174
  FFI.osqp_set_default_settings(set)
173
175
 
174
176
  # hack for setting members with []=
data/lib/osqp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module OSQP
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.1"
3
3
  end
data/lib/osqp.rb CHANGED
@@ -2,9 +2,9 @@
2
2
  require "fiddle/import"
3
3
 
4
4
  # modules
5
- require "osqp/matrix"
6
- require "osqp/solver"
7
- require "osqp/version"
5
+ require_relative "osqp/matrix"
6
+ require_relative "osqp/solver"
7
+ require_relative "osqp/version"
8
8
 
9
9
  module OSQP
10
10
  class Error < StandardError; end
Binary file
Binary file
Binary file
Binary file
Binary file
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: osqp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-23 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: fiddle
@@ -24,7 +23,6 @@ dependencies:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
25
  version: '0'
27
- description:
28
26
  email: andrew@ankane.org
29
27
  executables: []
30
28
  extensions: []
@@ -38,7 +36,6 @@ files:
38
36
  - lib/osqp/ffi.rb
39
37
  - lib/osqp/matrix.rb
40
38
  - lib/osqp/solver.rb
41
- - lib/osqp/utils.rb
42
39
  - lib/osqp/version.rb
43
40
  - vendor/aarch64-linux/LICENSE-amd.txt
44
41
  - vendor/aarch64-linux/LICENSE-osqp.txt
@@ -69,7 +66,6 @@ homepage: https://github.com/ankane/osqp-ruby
69
66
  licenses:
70
67
  - Apache-2.0
71
68
  metadata: {}
72
- post_install_message:
73
69
  rdoc_options: []
74
70
  require_paths:
75
71
  - lib
@@ -77,15 +73,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
77
73
  requirements:
78
74
  - - ">="
79
75
  - !ruby/object:Gem::Version
80
- version: '3.1'
76
+ version: '3.2'
81
77
  required_rubygems_version: !ruby/object:Gem::Requirement
82
78
  requirements:
83
79
  - - ">="
84
80
  - !ruby/object:Gem::Version
85
81
  version: '0'
86
82
  requirements: []
87
- rubygems_version: 3.5.16
88
- signing_key:
83
+ rubygems_version: 3.6.7
89
84
  specification_version: 4
90
85
  summary: OSQP (Operator Splitting Quadratic Program) solver for Ruby
91
86
  test_files: []
data/lib/osqp/utils.rb DELETED
@@ -1,15 +0,0 @@
1
- module OSQP
2
- module Utils
3
- class << self
4
- def float_array(arr)
5
- # OSQP float = double
6
- Fiddle::Pointer[arr.to_a.pack("d*")]
7
- end
8
-
9
- def int_array(arr)
10
- # OSQP int = long long
11
- Fiddle::Pointer[arr.to_a.pack("q*")]
12
- end
13
- end
14
- end
15
- end