osqp 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6ed92bcdae0ff5291f26741fc77be7da17b2dc1e4bb6680df7c20516f6b894e
4
- data.tar.gz: 7f66c0c4d72a6bb77abb7d3cf4119d79117c92079d7b4dde460d2d952277aed1
3
+ metadata.gz: eaa20f2fcffb79fc2ddea0547c9e2019aa63b710df8ba097809e096437f0eee4
4
+ data.tar.gz: 2311853dfdbf7794e584cb6a305a4359906e9f41ae856a7882eb2a5394ee3611
5
5
  SHA512:
6
- metadata.gz: e16b34d395a64988f04c2779d67dfd164162940e92cbd857ae324aa694ee04e05162fd8cb9532a2a7b828d598814bff5fd4cce8601a8b29e3f69913d530085b9
7
- data.tar.gz: f8b0dfb4a6657d7398bd3f366c8368bc82233e611890f19e603e21b45a566cd9a7b12e07cb894a669872eab28948d79df919aa973f686d980a94889f4cbdef1e
6
+ metadata.gz: 54bb5418bbbe93dcf7809441e1c0ab35c6e2f27891c54e3f2aae245fb4285d8805ed3909f0b8a6ad37ada5f174b70218a6e26a67116ec652a8fa2cfe8f6556ee
7
+ data.tar.gz: 3c9691bb46452def08f7aeac289040d5bad84e9fea78c2968659e9abe4d7e7126bda82b894af5bd79e44dac18f3c8924d53f2766246d093d69f2b23689549886
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.4.0 (2025-04-01)
2
+
3
+ - Updated OSQP to 1.0.0
4
+ - Dropped support for Ruby < 3.2
5
+
1
6
  ## 0.3.0 (2024-10-23)
2
7
 
3
8
  - 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,11 @@ 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 = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)
21
+ check_result FFI.osqp_setup(work.ref, matrix_ptr(p), q, matrix_ptr(a), l, u, a.m, a.n, set)
22
+ work.free = FFI["osqp_cleanup"]
23
+ @work = FFI::Solver.new(work)
32
24
  end
33
25
 
34
26
  def solve(*args, **settings)
@@ -38,9 +30,9 @@ module OSQP
38
30
 
39
31
  # solution
40
32
  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)
33
+ m, n = dimensions
34
+ x = read_float_array(solution.x, n)
35
+ y = read_float_array(solution.y, m)
44
36
 
45
37
  # info
46
38
  info = FFI::Info.new(@work.info)
@@ -54,8 +46,8 @@ module OSQP
54
46
  status_val: info.status_val,
55
47
  status_polish: info.status_polish,
56
48
  obj_val: info.obj_val,
57
- pri_res: info.pri_res,
58
- dua_res: info.dua_res,
49
+ pri_res: info.prim_res,
50
+ dua_res: info.dual_res,
59
51
  setup_time: info.setup_time,
60
52
  solve_time: info.solve_time,
61
53
  update_time: info.update_time,
@@ -72,15 +64,7 @@ module OSQP
72
64
  raise Error, "Expected x to be size #{n}, got #{x.size}" if x && x.size != n
73
65
  raise Error, "Expected y to be size #{m}, got #{y.size}" if y && y.size != m
74
66
 
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
67
+ check_result FFI.osqp_warm_start(@work, x ? float_array(x) : nil, y ? float_array(y) : nil)
84
68
  end
85
69
 
86
70
  private
@@ -133,6 +117,11 @@ module OSQP
133
117
  char_ptr[0, idx].map(&:chr).join
134
118
  end
135
119
 
120
+ def read_int(ptr)
121
+ # OSQP int = long long
122
+ ptr[0, Fiddle::SIZEOF_LONG_LONG].unpack1("q")
123
+ end
124
+
136
125
  def csc_matrix(mtx, upper: false)
137
126
  mtx = Matrix.from_dense(mtx) unless mtx.is_a?(Matrix)
138
127
 
@@ -156,15 +145,19 @@ module OSQP
156
145
  ci = int_array(csc[:index])
157
146
  cp = int_array(csc[:start])
158
147
 
159
- ptr = FFI.csc_matrix(mtx.m, mtx.n, nnz, cx, ci, cp)
148
+ ptr = FFI.OSQPCscMatrix_new(mtx.m, mtx.n, nnz, cx, ci, cp)
149
+ ptr.free = FFI["OSQPCscMatrix_free"]
160
150
  # save refs
161
151
  ptr.instance_variable_set(:@osqp_refs, [cx, ci, cp])
162
152
  ptr
163
153
  end
164
154
 
165
155
  def dimensions
166
- data = FFI::Data.new(@work.data)
167
- [data.m, data.n]
156
+ # OSQP int = long long
157
+ m = Fiddle::Pointer.malloc(Fiddle::SIZEOF_LONG_LONG)
158
+ n = Fiddle::Pointer.malloc(Fiddle::SIZEOF_LONG_LONG)
159
+ FFI.osqp_get_dimensions(@work, m, n)
160
+ [read_int(m), read_int(n)]
168
161
  end
169
162
 
170
163
  def create_settings(settings)
data/lib/osqp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module OSQP
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  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.0
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: 2025-04-01 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.2
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