Project

opl

0.01
No commit activity in last 3 years
No release in over 3 years
This gem gives you a beautifully simple way to formulate your linear or mixed integer program. The syntax is inspired by OPL Studio, which remains my favorite linear programming software, but the license is quite expensive.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

~> 0.4.0
 Project Readme

OPL (pronounced Opal) is a Linear Programming syntax based off of OPL Studio.

The entire purpose of this gem is to allow you to write your linear programs or optimization problems in a simple, human-understandable way. So instead of 30 lines of code to set up a problem (as in the rglpk documentation), you can set up your problem like so:

maximize(  
  "x + y",  
subject_to([  
  "x <= 10",  
  "y <= 3"  
]))

I try to keep the tests up to date, so take a look in there for more examples. Run tests with

rspec tests.rb

A quick view at functionality:

Summation and Forall constraints:

maximize(  
  "sum(i in (0..3) x[i])",  
subject_to([  
  "forall(i in (0..3), x[i] <= 3)"  
]))

Easy specification of variable types:

lp = maximize(  
	"10x1 + 6x2 + 4x3",  
subject_to([  
	"x1 + x2 + x3 <= 100",  
	"10x1 + 4x2 + 5x3 <= 600",  
	"2x1 + 2x2 + 6x3 <= 300",  
	"x1 >= 0",  
	"x2 >= 0",  
	"x3 >= 0"  
],[  
	"BOOLEAN: x1",  
	"INTEGER: x3"  
]  
))

Access to epsilon for strict inequalities:

lp = maximize(  
	"x + y + z",  
subject_to([  
	"x + z < 2",  
	"y <= 4",  
],[  
	"INTEGER: y",  
	"EPSILON: 0.03"  
]  
))  

BE WARNED - When you specify a variable as INTEGER or BOOLEAN, you will be using the Branch & Cut method to solve the problem. This is very inefficient, and some seemingly easy problems can take forever to solve. You may have to formulate your problem in a clever way. Here is an example.

This problem would take B&C hours to solve:

lp = maximize(  
	"x + y + x[3]",  
subject_to([   
	"x + x[3] <= 2.5",  
	"y <= 4"  
],[  
	"INTEGER: x, y",  
]  
))  

But if we just use some common sense, we can make this model:

lp = maximize(  
	"x + y + x[3]",  
subject_to([  
	"x <= 2.5",  
	"x[3] <= 2.5",  
	"x + x[3] <= 2.5",  
	"y <= 4"  
],[  
	"INTEGER: x, y",  
]  
))  

Which is solvable in a few milliseconds and clearly does not affect the result.

Use ruby data matrices:

d = [[3,5,3],[1,2,3],[2,5,9]]

lp = maximize(
	"sum(i in [1,2], j in (0..1), d[i][j+1]*x[i-1][j])",
subject_to([
	"forall(i in (1..2), x[i-1][1] <= 100)",
	"forall(i in (0..2), j in (0..2), x[i][j] <= 200)"
],[
	"NONNEGATIVE: x",
	"DATA: {d => #{d}}"
]
))

Sudoku wrapper:

problem = [
  [0,0,0,2,6,0,7,0,1],
  [6,8,0,0,7,0,0,9,0],
  [1,9,0,0,0,4,5,0,0],
  [8,2,0,1,0,0,0,4,0],
  [0,0,4,6,0,2,9,0,0],
  [0,5,0,0,0,3,0,2,8],
  [0,0,9,3,0,0,0,7,4],
  [0,4,0,0,5,0,0,3,6],
  [7,0,3,0,1,8,0,0,0]
]
sudoku = OPL::Sudoku.new problem
sudoku.solve
sudoku.format_solution
sudoku.print_solution