Skip to content

Commit

Permalink
Moving Pyro examples to example folder
Browse files Browse the repository at this point in the history
  • Loading branch information
mrmundt committed Mar 11, 2021
1 parent aecf2f4 commit 264094f
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 0 deletions.
101 changes: 101 additions & 0 deletions examples/pyro/sudoku.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from pyomo.environ import *

# create a standard python dict for mapping subsquares to
# the list (row,col) entries
subsq_to_row_col = dict()

subsq_to_row_col[1] = [(i,j) for i in range(1,4) for j in range(1,4)]
subsq_to_row_col[2] = [(i,j) for i in range(1,4) for j in range(4,7)]
subsq_to_row_col[3] = [(i,j) for i in range(1,4) for j in range(7,10)]

subsq_to_row_col[4] = [(i,j) for i in range(4,7) for j in range(1,4)]
subsq_to_row_col[5] = [(i,j) for i in range(4,7) for j in range(4,7)]
subsq_to_row_col[6] = [(i,j) for i in range(4,7) for j in range(7,10)]

subsq_to_row_col[7] = [(i,j) for i in range(7,10) for j in range(1,4)]
subsq_to_row_col[8] = [(i,j) for i in range(7,10) for j in range(4,7)]
subsq_to_row_col[9] = [(i,j) for i in range(7,10) for j in range(7,10)]

# creates the sudoku model for a 10x10 board, where the
# input board is a list of fixed numbers specified in
# (row, col, val) tuples.
def create_sudoku_model(board):

model = ConcreteModel()

# store the starting board for the model
model.board = board

# create sets for rows columns and squares
model.ROWS = RangeSet(1,9)
model.COLS = RangeSet(1,9)
model.SUBSQUARES = RangeSet(1,9)
model.VALUES = RangeSet(1,9)

# create the binary variables to define the values
model.y = Var(model.ROWS, model.COLS, model.VALUES, within=Binary)

# fix variables based on the current board
for (r,c,v) in board:
model.y[r,c,v].fix(1)

# create the objective - this is a feasibility problem
# so we just make it a constant
model.obj = Objective(expr= 1.0)

# @row_col_cons:
# exactly one number in each row
def _RowCon(model, r, v):
return sum(model.y[r,c,v] for c in model.COLS) == 1
model.RowCon = Constraint(model.ROWS, model.VALUES, rule=_RowCon)

# exactly one nubmer in each column
def _ColCon(model, c, v):
return sum(model.y[r,c,v] for r in model.ROWS) == 1
model.ColCon = Constraint(model.COLS, model.VALUES, rule=_ColCon)
# @:row_col_cons

# @subsq_con:
# exactly one number in each subsquare
def _SqCon(model, s, v):
return sum(model.y[r,c,v] for (r,c) in subsq_to_row_col[s]) == 1
model.SqCon = Constraint(model.SUBSQUARES, model.VALUES, rule=_SqCon)
# @:subsq_con

# @num_con:
# exactly one number in each cell
def _ValueCon(model, r, c):
return sum(model.y[r,c,v] for v in model.VALUES) == 1
model.ValueCon = Constraint(model.ROWS, model.COLS, rule=_ValueCon)
# @:num_con

return model

# use this function to add a new integer cut to the model.
def add_integer_cut(model):
# add the ConstraintList to store the IntegerCuts if
# it does not already exist
if not hasattr(model, "IntegerCuts"):
model.IntegerCuts = ConstraintList()

# add the integer cut corresponding to the current
# solution in the model
cut_expr = 0.0
for r in model.ROWS:
for c in model.COLS:
for v in model.VALUES:
if not model.y[r,c,v].fixed:
# check if the binary variable is on or off
# note, it may not be exactly 1
if value(model.y[r,c,v]) >= 0.5:
cut_expr += (1.0 - model.y[r,c,v])
else:
cut_expr += model.y[r,c,v]
model.IntegerCuts.add(cut_expr >= 1)

# prints the current solution stored in the model
def print_solution(model):
for r in model.ROWS:
print(' '.join(str(v) for c in model.COLS
for v in model.VALUES
if value(model.y[r,c,v]) >= 0.5))
File renamed without changes.
File renamed without changes.
35 changes: 35 additions & 0 deletions examples/pyro/sudoku_run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from pyomo.opt import (SolverFactory,
TerminationCondition)
from sudoku import (create_sudoku_model,
print_solution,
add_integer_cut)

# define the board
board = [(1,1,5),(1,2,3),(1,5,7), \
(2,1,6),(2,4,1),(2,5,9),(2,6,5), \
(3,2,9),(3,3,8),(3,8,6), \
(4,1,8),(4,5,6),(4,9,3), \
(5,1,4),(5,4,8),(5,6,3),(5,9,1), \
(6,1,7),(6,5,2),(6,9,6), \
(7,2,6),(7,7,2),(7,8,8), \
(8,4,4),(8,5,1),(8,6,9),(8,9,5), \
(9,5,8),(9,8,7),(9,9,9)]

model = create_sudoku_model(board)

solution_count = 0
while 1:

with SolverFactory("glpk") as opt:
results = opt.solve(model)
if results.solver.termination_condition != \
TerminationCondition.optimal:
print("All board solutions have been found")
break

solution_count += 1

add_integer_cut(model)

print("Solution #%d" % (solution_count))
print_solution(model)
15 changes: 15 additions & 0 deletions examples/pyro/sudoku_run.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
WARNING: Constant objective detected, replacing with a placeholder to prevent
solver failure.
Solution #1
5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
1 9 8 3 4 2 5 6 7
8 5 9 7 6 1 4 2 3
4 2 6 8 5 3 7 9 1
7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5
3 4 5 2 8 6 1 7 9
WARNING: Constant objective detected, replacing with a placeholder to prevent
solver failure.
All board solutions have been found
File renamed without changes.

0 comments on commit 264094f

Please # to comment.