osqp 0.2.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +15 -5
- data/lib/osqp/matrix.rb +64 -0
- data/lib/osqp/solver.rb +15 -57
- data/lib/osqp/utils.rb +15 -0
- data/lib/osqp/version.rb +1 -1
- data/lib/osqp.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b2906722de1daf0e3f2441edee63d8cec2452012cd9fa91634f37418e66f6fc
|
4
|
+
data.tar.gz: ee0cf11cc8ea7d1676843699265ad27623d237940c756fdb9c49c8e404137b37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 835c7ac35d791e794b7da902a1a248696860ed09d05e8831d0d4b6c54615758f6d930443e1f4b4f21d0b9d10453882653db60e2bda46b107d342a3cda304e889
|
7
|
+
data.tar.gz: 027ec047ca635e1b9f36377921110444a90226dfa85ebeac44ccab5b1945aac2d37f487f7725ba5604f264551f852392855e087c84afd1c39cd7790278fa3c68
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -17,9 +17,9 @@ gem "osqp"
|
|
17
17
|
Prep the problem - here’s how it should be [setup](https://osqp.org/docs/examples/setup-and-solve.html)
|
18
18
|
|
19
19
|
```ruby
|
20
|
-
p = [[4, 1], [0, 2]]
|
20
|
+
p = OSQP::Matrix.from_dense([[4, 1], [0, 2]])
|
21
21
|
q = [1, 1]
|
22
|
-
a = [[1, 1], [1, 0], [0, 1]]
|
22
|
+
a = OSQP::Matrix.from_dense([[1, 1], [1, 0], [0, 1]])
|
23
23
|
l = [1, 0, 0]
|
24
24
|
u = [1, 0.7, 0.7]
|
25
25
|
```
|
@@ -41,16 +41,26 @@ solver.warm_start(x, y)
|
|
41
41
|
|
42
42
|
## Data
|
43
43
|
|
44
|
-
|
44
|
+
Matrices can be a sparse matrix
|
45
45
|
|
46
46
|
```ruby
|
47
|
-
|
47
|
+
a = OSQP::Matrix.new(3, 2)
|
48
|
+
a[0, 0] = 1
|
49
|
+
a[1, 0] = 2
|
50
|
+
# or
|
51
|
+
OSQP::Matrix.from_dense([[1, 0], [2, 0], [0, 0]])
|
52
|
+
```
|
53
|
+
|
54
|
+
Arrays can be Ruby arrays
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
[1, 2, 3]
|
48
58
|
```
|
49
59
|
|
50
60
|
Or Numo arrays
|
51
61
|
|
52
62
|
```ruby
|
53
|
-
Numo::NArray.cast([
|
63
|
+
Numo::NArray.cast([1, 2, 3])
|
54
64
|
```
|
55
65
|
|
56
66
|
## Resources
|
data/lib/osqp/matrix.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module OSQP
|
2
|
+
class Matrix
|
3
|
+
attr_reader :m, :n
|
4
|
+
|
5
|
+
def initialize(m, n)
|
6
|
+
@m = m
|
7
|
+
@n = n
|
8
|
+
@data = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def []=(row_index, column_index, value)
|
12
|
+
raise IndexError, "row index out of bounds" if row_index < 0 || row_index >= @m
|
13
|
+
raise IndexError, "column index out of bounds" if column_index < 0 || column_index >= @n
|
14
|
+
if value == 0
|
15
|
+
(@data[column_index] ||= {}).delete(row_index)
|
16
|
+
else
|
17
|
+
(@data[column_index] ||= {})[row_index] = value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_ptr
|
22
|
+
cx = []
|
23
|
+
ci = []
|
24
|
+
cp = []
|
25
|
+
|
26
|
+
# CSC format
|
27
|
+
# https://www.gormanalysis.com/blog/sparse-matrix-storage-formats/
|
28
|
+
cp << 0
|
29
|
+
n.times do |j|
|
30
|
+
(@data[j] || {}).sort_by { |k, v| k }.each do |k, v|
|
31
|
+
cx << v
|
32
|
+
ci << k
|
33
|
+
end
|
34
|
+
# cumulative column values
|
35
|
+
cp << cx.size
|
36
|
+
end
|
37
|
+
|
38
|
+
nnz = cx.size
|
39
|
+
cx = Utils.float_array(cx)
|
40
|
+
ci = Utils.int_array(ci)
|
41
|
+
cp = Utils.int_array(cp)
|
42
|
+
|
43
|
+
ptr = FFI.csc_matrix(m, n, nnz, cx, ci, cp)
|
44
|
+
# save refs
|
45
|
+
ptr.instance_variable_set(:@osqp_refs, [cx, ci, cp])
|
46
|
+
ptr
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.from_dense(data)
|
50
|
+
data = data.to_a
|
51
|
+
m = data.size
|
52
|
+
n = m > 0 ? data.first.size : 0
|
53
|
+
|
54
|
+
mtx = Matrix.new(m, n)
|
55
|
+
data.each_with_index do |row, i|
|
56
|
+
raise ArgumentError, "row has different number of columns" if row.size != n
|
57
|
+
row.each_with_index do |v, j|
|
58
|
+
mtx[i, j] = v if v != 0
|
59
|
+
end
|
60
|
+
end
|
61
|
+
mtx
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/osqp/solver.rb
CHANGED
@@ -10,16 +10,15 @@ module OSQP
|
|
10
10
|
|
11
11
|
# data
|
12
12
|
# do not assign directly to struct to keep refs
|
13
|
-
m, n = shape(a)
|
14
13
|
p = csc_matrix(p, upper: true)
|
15
|
-
q = float_array(q)
|
14
|
+
q = Utils.float_array(q)
|
16
15
|
a = csc_matrix(a)
|
17
|
-
l = float_array(l)
|
18
|
-
u = float_array(u)
|
16
|
+
l = Utils.float_array(l)
|
17
|
+
u = Utils.float_array(u)
|
19
18
|
|
20
19
|
data = FFI::Data.malloc
|
21
|
-
data.n = n
|
22
|
-
data.m = m
|
20
|
+
data.n = a.n
|
21
|
+
data.m = a.m
|
23
22
|
data.p = p
|
24
23
|
data.q = q
|
25
24
|
data.a = a
|
@@ -74,11 +73,11 @@ module OSQP
|
|
74
73
|
raise Error, "Expected y to be size #{m}, got #{y.size}" if y && y.size != m
|
75
74
|
|
76
75
|
if x && y
|
77
|
-
check_result FFI.osqp_warm_start(@work, float_array(x), float_array(y))
|
76
|
+
check_result FFI.osqp_warm_start(@work, Utils.float_array(x), Utils.float_array(y))
|
78
77
|
elsif x
|
79
|
-
check_result FFI.osqp_warm_start_x(@work, float_array(x))
|
78
|
+
check_result FFI.osqp_warm_start_x(@work, Utils.float_array(x))
|
80
79
|
elsif y
|
81
|
-
check_result FFI.osqp_warm_start_y(@work, float_array(y))
|
80
|
+
check_result FFI.osqp_warm_start_y(@work, Utils.float_array(y))
|
82
81
|
else
|
83
82
|
raise Error, "Must set x or y"
|
84
83
|
end
|
@@ -114,16 +113,6 @@ module OSQP
|
|
114
113
|
end
|
115
114
|
end
|
116
115
|
|
117
|
-
def float_array(arr)
|
118
|
-
# OSQP float = double
|
119
|
-
Fiddle::Pointer[arr.to_a.pack("d*")]
|
120
|
-
end
|
121
|
-
|
122
|
-
def int_array(arr)
|
123
|
-
# OSQP int = long long
|
124
|
-
Fiddle::Pointer[arr.to_a.pack("q*")]
|
125
|
-
end
|
126
|
-
|
127
116
|
def read_float_array(ptr, size)
|
128
117
|
# OSQP float = double
|
129
118
|
ptr[0, size * Fiddle::SIZEOF_DOUBLE].unpack("d*")
|
@@ -134,39 +123,18 @@ module OSQP
|
|
134
123
|
char_ptr[0, idx].map(&:chr).join
|
135
124
|
end
|
136
125
|
|
137
|
-
# TODO add support sparse matrices
|
138
126
|
def csc_matrix(mtx, upper: false)
|
139
|
-
mtx = mtx.
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
cp = []
|
146
|
-
|
147
|
-
# CSC format
|
148
|
-
# https://www.gormanalysis.com/blog/sparse-matrix-storage-formats/
|
149
|
-
cp << 0
|
150
|
-
n.times do |j|
|
151
|
-
mtx.each_with_index do |row, i|
|
152
|
-
if row[j] != 0 && (!upper || i <= j)
|
153
|
-
cx << row[j]
|
154
|
-
ci << i
|
127
|
+
mtx = Matrix.from_dense(mtx) unless mtx.is_a?(Matrix)
|
128
|
+
|
129
|
+
if upper
|
130
|
+
mtx.m.times do |i|
|
131
|
+
mtx.n.times do |j|
|
132
|
+
mtx[i, j] = 0 if i > j
|
155
133
|
end
|
156
134
|
end
|
157
|
-
# cumulative column values
|
158
|
-
cp << cx.size
|
159
135
|
end
|
160
136
|
|
161
|
-
|
162
|
-
cx = float_array(cx)
|
163
|
-
ci = int_array(ci)
|
164
|
-
cp = int_array(cp)
|
165
|
-
|
166
|
-
ptr = FFI.csc_matrix(m, n, nnz, cx, ci, cp)
|
167
|
-
# save refs
|
168
|
-
ptr.instance_variable_set(:@osqp_refs, [cx, ci, cp])
|
169
|
-
ptr
|
137
|
+
mtx
|
170
138
|
end
|
171
139
|
|
172
140
|
def dimensions
|
@@ -174,16 +142,6 @@ module OSQP
|
|
174
142
|
[data.m, data.n]
|
175
143
|
end
|
176
144
|
|
177
|
-
def shape(a)
|
178
|
-
if defined?(Matrix) && a.is_a?(Matrix)
|
179
|
-
[a.row_count, a.column_count]
|
180
|
-
elsif defined?(Numo::NArray) && a.is_a?(Numo::NArray)
|
181
|
-
a.shape
|
182
|
-
else
|
183
|
-
[a.size, a.first.size]
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
145
|
def create_settings(settings)
|
188
146
|
set = FFI::Settings.malloc
|
189
147
|
FFI.osqp_set_default_settings(set)
|
data/lib/osqp/utils.rb
ADDED
@@ -0,0 +1,15 @@
|
|
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
|
data/lib/osqp/version.rb
CHANGED
data/lib/osqp.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: osqp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: andrew@ankane.org
|
@@ -22,7 +22,9 @@ files:
|
|
22
22
|
- README.md
|
23
23
|
- lib/osqp.rb
|
24
24
|
- lib/osqp/ffi.rb
|
25
|
+
- lib/osqp/matrix.rb
|
25
26
|
- lib/osqp/solver.rb
|
27
|
+
- lib/osqp/utils.rb
|
26
28
|
- lib/osqp/version.rb
|
27
29
|
- vendor/aarch64-linux/LICENSE-amd.txt
|
28
30
|
- vendor/aarch64-linux/LICENSE-osqp.txt
|