lib/osqp/solver.rb in osqp-0.2.1 vs lib/osqp/solver.rb in osqp-0.2.2

- old
+ new

@@ -9,21 +9,21 @@ u = u.map { |v| v > FFI::OSQP_INFTY ? FFI::OSQP_INFTY : v } # data # do not assign directly to struct to keep refs p = csc_matrix(p, upper: true) - q = Utils.float_array(q) + q = float_array(q) a = csc_matrix(a) - l = Utils.float_array(l) - u = Utils.float_array(u) + l = float_array(l) + u = float_array(u) data = FFI::Data.malloc data.n = a.n data.m = a.m - data.p = p + data.p = matrix_ptr(p) data.q = q - data.a = a + data.a = matrix_ptr(a) data.l = l data.u = u # work work = FFI::Workspace.malloc @@ -71,15 +71,15 @@ m, n = dimensions raise Error, "Expected x to be size #{n}, got #{x.size}" if x && x.size != n raise Error, "Expected y to be size #{m}, got #{y.size}" if y && y.size != m if x && y - check_result FFI.osqp_warm_start(@work, Utils.float_array(x), Utils.float_array(y)) + check_result FFI.osqp_warm_start(@work, float_array(x), float_array(y)) elsif x - check_result FFI.osqp_warm_start_x(@work, Utils.float_array(x)) + check_result FFI.osqp_warm_start_x(@work, float_array(x)) elsif y - check_result FFI.osqp_warm_start_y(@work, Utils.float_array(y)) + check_result FFI.osqp_warm_start_y(@work, float_array(y)) else raise Error, "Must set x or y" end end @@ -111,10 +111,20 @@ raise Error, message end end + def float_array(arr) + # OSQP float = double + Fiddle::Pointer[arr.to_a.pack("d*")] + end + + def int_array(arr) + # OSQP int = long long + Fiddle::Pointer[arr.to_a.pack("q*")] + end + def read_float_array(ptr, size) # OSQP float = double ptr[0, size * Fiddle::SIZEOF_DOUBLE].unpack("d*") end @@ -125,17 +135,32 @@ def csc_matrix(mtx, upper: false) mtx = Matrix.from_dense(mtx) unless mtx.is_a?(Matrix) if upper + # TODO improve performance + mtx = mtx.dup mtx.m.times do |i| mtx.n.times do |j| mtx[i, j] = 0 if i > j end end end mtx + end + + def matrix_ptr(mtx) + csc = mtx.to_csc + nnz = csc[:value].size + cx = float_array(csc[:value]) + ci = int_array(csc[:index]) + cp = int_array(csc[:start]) + + ptr = FFI.csc_matrix(mtx.m, mtx.n, nnz, cx, ci, cp) + # save refs + ptr.instance_variable_set(:@osqp_refs, [cx, ci, cp]) + ptr end def dimensions data = FFI::Data.new(@work.data) [data.m, data.n]