Class: Opt::Solvers::OsqpSolver

Inherits:
AbstractSolver show all
Defined in:
lib/opt/solvers/osqp_solver.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from AbstractSolver

supports_semi_continuous_variables?, supports_semi_integer_variables?, supports_type?

Class Method Details

.available?Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/opt/solvers/osqp_solver.rb', line 64

def self.available?
  defined?(OSQP)
end

.supported_typesObject



68
69
70
# File 'lib/opt/solvers/osqp_solver.rb', line 68

def self.supported_types
  [:lp, :qp]
end

Instance Method Details

#solve(sense:, col_lower:, col_upper:, obj:, row_lower:, row_upper:, constraints_by_var:, vars:, offset:, verbose:, time_limit:, type:, indexed_objective:) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/opt/solvers/osqp_solver.rb', line 4

def solve(sense:, col_lower:, col_upper:, obj:, row_lower:, row_upper:, constraints_by_var:, vars:, offset:, verbose:, time_limit:, type:, indexed_objective:, **)
  obj = obj.map { |v| -v } if sense == :maximize

  a =
    constraints_by_var.map(&:first).map do |ic|
      vars.map do |var|
        ic[var] || 0
      end
    end

  # add variable constraints
  vars.each_with_index do |v, i|
    row = [0] * vars.size
    row[i] = 1
    a << row
    row_lower << col_lower[i]
    row_upper << col_upper[i]
  end

  p = OSQP::Matrix.new(a.first.size, a.first.size)
  if type == :qp
    vars.map.with_index do |v1, i|
      vars.map.with_index do |v2, j|
        if i > j
          0
        else
          v = indexed_objective[[v1, v2]]
          v = (v1.equal?(v2) ? v * 2 : v)
          v *= -1 if sense == :maximize
          p[i, j] = v
        end
      end
    end
  end

  solver = OSQP::Solver.new
  res = solver.solve(p, obj, a, row_lower, row_upper, verbose: verbose, time_limit: time_limit, polish: true)
  objective = res[:obj_val]
  objective *= -1 if sense == :maximize
  objective += offset

  status =
    case res[:status]
    when "solved"
      :optimal
    when "primal infeasible"
      :infeasible
    when "dual infeasible"
      :unbounded
    else
      res[:status]
    end

  {
    status: status,
    objective: objective,
    x: res[:x]
  }
end