8000 GitHub - ryanjoneil/rams: Ruby Algebraic Modeling System
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

ryanjoneil/rams

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ruby Algebraic Modeling System

Gem Version

RAMS logo

RAMS is a library for formulating and solving Mixed Integer Linear Programs in Ruby. Currently it supports the following open source solvers.

Quick start

Installation

RAMS assumes you have the solver you're using in your PATH. The default solver is HiGHS, but you can easily switch to any of the solvers listed above.

First make sure you have the latest RAMS installed.

gem install rams

Now install HiGHS or whatever solver you wish. The command below works on Fedora Linux. Consult the solver instructions for installation on your platform.

sudo dnf install highs

A first model

You are now ready to formulate and solve models. Try running a script like this.

require 'rams'

m = RAMS::Model.new

x1 = m.variable type: :binary
x2 = m.variable type: :binary
x3 = m.variable type: :binary

m.constrain(x1 + x2 + x3 <= 2)
m.constrain(x2 + x3 <= 1)

m.sense = :max
m.objective = 1 * x1 + 2 * x2 + 3 * x3

solution = m.solve
puts <<-HERE
objective: #{solution.objective}
x1 = #{solution[x1]}
x2 = #{solution[x2]}
x3 = #{solution[x3]}
HERE

You should get output along the lines of the following.

objective: 4.0
x1 = 1.0
x2 = 0.0
x3 = 1.0

Modeling primitives

The first class you need to instantiate is RAMS::Model. Everything else is created by interacting with instances of the Model class.

require 'rams'

m = RAMS::Model.new

Variables

Variables can be continuous (the default), integer, or binary. They are associated with an individual model.

x1 = m.variable
x2 = m.variable type: :integer
x3 = m.variable type: :binary

By default, a continuous variable has a lower bound of 0 and an upper bound of nil, representing positive infinity.

puts "#{m.variables.values.map { |x| [x.low, x.high ]}}"
[[0.0, nil], [0.0, nil], [0.0, nil]]

To set a variable's lower bound to negative infinity, pass a low: inf keyword argument to the Model.variable method. Similarly, upper bounds can be passed in to Model.variable using the high keyword argument.

x4 = m.variable(type: :integer, low: nil, high: 10)

The binary variables may appear to have an upper bound of positive infinity, but that becomes 1 when it is written to the solver. To see a model the way it is passed to a solver, use the to_lp method. This returns the model in LP format. Note that the variable names are different in the to_lp output.

puts m.to_lp
max
  obj: 0 v1
st

bounds
  0.0 <= v1 <= +inf
  0.0 <= v2 <= +inf
  0.0 <= v3 <= 1.0
  -inf <= v4 <= 10
general
  v2
  v4
binary
  v3
end

Constraints

Now we're ready to add some constraints. These can be done using linear inequalities and the Model.constrain method.

c1 = m.constrain(2*x1 + x2/2 <= 5)
c2 = m.constrain(x2 + x3 >= 2 - x4)
c3 = m.constrain(x2 == 2*x3)

When an inequality is instantiated, all the variables are moved into its lhs attribute, and the constant is stored in its rhs attribute. The sense of the inequality is also available.

puts <<-HERE
#{c1.lhs[x1]} * x1 + #{c1.lhs[x2]} * x2 #{c1.sense} #{c1.rhs}
#{c2.lhs[x2]} * x2 + #{c2.lhs[x3]} * x3 + #{c2.lhs[x4]} * x4 #{c2.sense} #{c2.rhs}
#{c3.lhs[x2]} * x2 + #{c3.lhs[x3]} #{c3.sense} #{c3.rhs}
HERE
2.0 * x1 + 0.5 * x2 <= 5.0
1.0 * x2 + 1.0 * x3 + 1.0 * x4 >= 2.0
1.0 * x2 + -2.0 == 0.0

Objective functions

The objective sense is available through the sense attribute. :max is the default. To minimize, set the sense to :min. Similarly, assign to the objective attribute to set the objective function. RAMS defaults to no objective function, or feasibility models. Explicitly setting the sense is always a good idea.

m.objective = x1 + 2*x2 + 3*x3 - x4
m.sense = :max

Solutions

To get a model solution, simply call solve. The objective, primal variable values, and dual prices can be accessed directly off of this object, along with the solution status.

puts <<-HERE
z = #{solution.objective}
x = #{[x1, x2, x3, x4].map { |x| solution[x] }}
y = #{[c1, c2, c3].map { |c| solution.dual[c] }}
HERE
z = 10.0
x = [2.0, 2.0, 1.0, -1.0]
y = [5.0, 0.0, 0.0]

Solver configuration

Verbosity

If you want to see what the solver is doing, simply set verbose to true on the model before solving.

m.verbose = true
solution = m.solve

This should give you output line the following, depending on your model and solver. Note that the output is not streamed in real time, but merely printed after solving.

Running HiGHS 1.11.0 (git hash: 364c83a51): Copyright (c) 2025 HiGHS under MIT licence terms
Set option log_file to "HiGHS.log"
Set option solution_file to "/tmp/20250624-180194-hu2ppg.lp.sol"
MIP  20250624-180194-hu2ppg has 49 rows; 40 cols; 144 nonzeros; 40 integer variables (40 binary)
[...snip...]

Switching solvers

If you want to switch to a different solver, install that solver onto your system and change the solver attribute on your model.

m.solver = :cbc   # or
m.solver = :clp   # or
m.solver = :glpk  # or
m.solver = :highs # or
m.solver = :scip

Solver path customization

By default, RAMS assumes that solvers are available in your system's PATH with their standard names. However, you can customize the path or name for any solver using environment vari 7C64 ables.

  • RAMS_SOLVER_PATH_CBC - Override path for CBC (defaults to coin.cbc)
  • RAMS_SOLVER_PATH_CLP - Override path for CLP (defaults to clp)
  • RAMS_SOLVER_PATH_GLPK - Override path for GLPK (defaults to glpsol)
  • RAMS_SOLVER_PATH_HIGHS - Override path for HiGHS (defaults to highs)
  • RAMS_SOLVER_PATH_SCIP - Override path for SCIP (defaults to scip)

For example, if you have GLPK installed in a custom location:

export RAMS_SOLVER_PATH_GLPK=/opt/glpk/bin/glpsol

Or if you have HiGHS installed in a custom location:

export RAMS_SOLVER_PATH_HIGHS=/opt/highs/bin/highs

These environment variables are particularly useful when you have multiple versions of solvers installed or when solvers are installed in non-standard locations.

Solver Arguments

Additional solver arguments can be passed as though they are command line flags. The following adds both --dfs and --bib arguments to the GLPK invocation.

m.solver = :glpk
m.args = ['--dfs', '--bib']
m.solve
GLPSOL: GLPK LP/MIP Solver, v4.60
Parameter(s) specified in the command line:
 --lp /var/folders/vj/t2g113b97mq1qzscqh7b8npc0000gn/T/20170126-46037-crkxuo.lp
 --output /var/folders/vj/t2g113b97mq1qzscqh7b8npc0000gn/T/20170126-46037-crkxuo.lp.sol
 --dfs --bib
Reading problem data from '/var/folders/vj/t2g113b97mq1qzscqh7b8npc0000gn/T/20170126-46037-crkxuo.lp'...
[...snip...]

This can be used to do things like set time limits on finding solutions. For instance, we can do that with GLPK as follows.

m.solver = :glpk
m.args = ['--tmlim', '3']
m.solve

For a more interesting example, if you are using SCIP, you can turn off presolving using the following configuration. This can be useful since SCIP doesn't provide dual prices for constraints that have been presolved out of the problem formulation.

m.solver = :scip
m.args = ['-c', 'set presolving maxrounds 0']
m.solve

Similarly, if you are using HiGHS, you can set a time limit or choose a specific algorithm.

m.solver = :highs
m.args = ['--time_limit', '10', '--solver', 'simplex']
m.solve

Every solver has different options, so check the manual to see what command line flags are available to you.

More modeling examples are available in the examples folder. Happy modeling!

About

Ruby Algebraic Modeling System

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages

0