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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a723c2590dd5dea89dd98525009db82f6e3bf740e7a47032a822e23bab790eb0
4
- data.tar.gz: 4515ead926d38e72843c8193ec67f072d24189108ddcc538ad0c021ccae4c35c
3
+ metadata.gz: 1b2906722de1daf0e3f2441edee63d8cec2452012cd9fa91634f37418e66f6fc
4
+ data.tar.gz: ee0cf11cc8ea7d1676843699265ad27623d237940c756fdb9c49c8e404137b37
5
5
  SHA512:
6
- metadata.gz: ac250fdfa3927134aff7d609456382d3bd9d79e1252e42a2adeba7d79e33db4361c504aa06701bea0cf0fa7d92a843726115af0fcba93734cb619af0883b1068
7
- data.tar.gz: 84a1e39d8bbd810e49a0c2ab5dafd897208d87476dbfede8a292482cd74ee078d2e88b11424100b8ae72c6bdfb6c7dc76301ae5d40f513e575d6dea1bb4d851e
6
+ metadata.gz: 835c7ac35d791e794b7da902a1a248696860ed09d05e8831d0d4b6c54615758f6d930443e1f4b4f21d0b9d10453882653db60e2bda46b107d342a3cda304e889
7
+ data.tar.gz: 027ec047ca635e1b9f36377921110444a90226dfa85ebeac44ccab5b1945aac2d37f487f7725ba5604f264551f852392855e087c84afd1c39cd7790278fa3c68
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.2.1 (2022-07-05)
2
+
3
+ - Added `Matrix` class
4
+
1
5
  ## 0.2.0 (2022-06-12)
2
6
 
3
7
  - Added ARM shared library for Linux
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
- Arrays and matrices can be Ruby arrays
44
+ Matrices can be a sparse matrix
45
45
 
46
46
  ```ruby
47
- [[1, 2, 3], [4, 5, 6]]
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([[1, 2, 3], [4, 5, 6]])
63
+ Numo::NArray.cast([1, 2, 3])
54
64
  ```
55
65
 
56
66
  ## Resources
@@ -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.to_a
140
-
141
- m, n = shape(mtx)
142
-
143
- cx = []
144
- ci = []
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
- nnz = cx.size
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
@@ -1,3 +1,3 @@
1
1
  module OSQP
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
data/lib/osqp.rb CHANGED
@@ -2,7 +2,9 @@
2
2
  require "fiddle/import"
3
3
 
4
4
  # modules
5
+ require "osqp/matrix"
5
6
  require "osqp/solver"
7
+ require "osqp/utils"
6
8
  require "osqp/version"
7
9
 
8
10
  module OSQP
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.0
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-06-12 00:00:00.000000000 Z
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