feat: assignment 2

This commit is contained in:
Renge 2024-03-09 16:25:30 -05:00
parent bae2763db1
commit b5ea6f9865
20 changed files with 488 additions and 0 deletions

34
Assignment2/A/tsp.P Normal file
View File

@ -0,0 +1,34 @@
/*Jacob Besse
Prolog*/
/*This is the data set.*/
edge(a,b,2). edge(a,c,3). edge(a,d,1).
edge(b,d,2). edge(b,e,2). edge(b,f,4).
edge(c,a,3). edge(c,d,2). edge(c,e,2).
edge(d,a,1). edge(d,b,2).
edge(e,c,2). edge(e,d,2). edge(e,f,1).
edge(f,b,4). edge(f,c,3). edge(f,e,1).
len([], 0).
len([_|T], N):- len(T, X), N is X+1 .
best_path(Visited, Total):- path(a, a, Visited, Total).
path(Start, Fin, Visited, Total) :- path(Start, Fin, [Start], Visited, 0, Total).
path(Start, Fin, CurrentLoc, Visited, Costn, Total) :-
edge(Start, StopLoc, Distance), NewCostn is Costn + Distance, \+ member(StopLoc, CurrentLoc),
path(StopLoc, Fin, [StopLoc|CurrentLoc], Visited, NewCostn, Total).
path(Start, Fin, CurrentLoc, Visited, Costn, Total) :-
edge(Start, Fin, Distance), reverse([Fin|CurrentLoc], Visited), len(Visited, Q),
(Q\=7 -> Total is 100000; Total is Costn + Distance).
shortest_path(Path):-setof(Cost-Path, best_path(Path,Cost), Holder),pick(Holder,Path).
best(Cost-Holder,Bcost-_,Cost-Holder):- Cost<Bcost,!.
best(_,X,X).
pick([Cost-Holder|R],X):- pick(R,Bcost-Bholder),best(Cost-Holder,Bcost-Bholder,X),!.
pick([X],X).

36
Assignment2/A/tsp.dat Normal file
View File

@ -0,0 +1,36 @@
let dist[1,1]:=99;
let dist[1,2]:=2;
let dist[1,3]:=3;
let dist[1,4]:=1;
let dist[1,5]:=99;
let dist[1,6]:=99;
let dist[2,1]:=99;
let dist[2,2]:=99;
let dist[2,3]:=99;
let dist[2,4]:=2;
let dist[2,5]:=2;
let dist[2,6]:=4;
let dist[3,1]:=3;
let dist[3,2]:=99;
let dist[3,3]:=99;
let dist[3,4]:=2;
let dist[3,5]:=2;
let dist[3,6]:=99;
let dist[4,1]:=1;
let dist[4,2]:=2;
let dist[4,3]:=99;
let dist[4,4]:=99;
let dist[4,5]:=99;
let dist[4,6]:=99;
let dist[5,1]:=99;
let dist[5,2]:=99;
let dist[5,3]:=2;
let dist[5,4]:=2;
let dist[5,5]:=99;
let dist[5,6]:=1;
let dist[6,1]:=99;
let dist[6,2]:=4;
let dist[6,3]:=3;
let dist[6,4]:=99;
let dist[6,5]:=1;
let dist[6,6]:=99;

22
Assignment2/A/tsp.lp Normal file
View File

@ -0,0 +1,22 @@
% % Generate
{ cycle(X,Y) : path(X,Y) } = 1 :- node(X).
{ cycle(X,Y) : path(X,Y) } = 1 :- node(Y).
% Display
#show cycle/2.
% Optimize
#minimize { C,X,Y : cycle(X,Y), edge(X,Y,C) }.
% Nodes
node(a;b;c;d;e;f).
% (Directed) Edges
path(a,(b;c;d)). path(b,(d;e;f)). path(c,(a;d;e)).
path(d,(a;b)). path(e,(c;d;f)). path(f,(b;c;e)).
% Edge Costs
edge(a,b,2). edge(a,c,3). edge(a,d,1).
edge(b,d,2). edge(b,e,2). edge(b,f,4).
edge(c,a,3). edge(c,d,2). edge(c,e,2).
edge(d,a,1). edge(d,b,2).
edge(e,c,2). edge(e,d,2). edge(e,f,1).
edge(f,b,4). edge(f,c,3). edge(f,e,1).

26
Assignment2/A/tsp.mod Normal file
View File

@ -0,0 +1,26 @@
param N := 6;
var m{1..N};
param dist{1..N,1..N} integer > 0;
var x{1..N,1..N} binary;
minimize Total:
sum{ i in 1..N,j in 1..N: i<>j} dist[i,j]* x[i,j];
C1{k in 1..N}: sum{i in 1..N: i <> k} x[i,k] =1;
C2{k in 1..N}: sum{i in 1..N: i <> k} x[k,i] =1;
C3{i in 2..N, j in 2..N: i <> j}: m[i]-m[j]+N*x[i,j]<=N-1;
C4{i in 2..N}: m[i]<=N-1;
data tsp.dat;
option solver cplex;
solve;
display Total;
display x;
display m;

80
Assignment2/A/tsp.py Normal file
View File

@ -0,0 +1,80 @@
"""Simple Travelling Salesperson Problem (TSP) between cities."""
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
def create_data_model():
"""Stores the data for the problem."""
data = {}
data["distance_matrix"] = [
[99, 2, 3, 1, 99, 99],
[99, 99, 99, 2, 2, 4],
[3, 99, 99, 2, 2, 99],
[1, 2, 99, 99, 99, 99],
[99, 99, 2, 2, 99, 1],
[99, 4, 3, 99, 1, 99],
]
data["num_vehicles"] = 1
data["depot"] = 0
return data
def print_solution(manager, routing, solution):
"""Prints solution on console."""
print(f"Objective: {solution.ObjectiveValue()} miles")
index = routing.Start(0)
plan_output = "Route for vehicle 0:\n"
route_distance = 0
while not routing.IsEnd(index):
plan_output += f" {manager.IndexToNode(index) + 1} ->"
previous_index = index
index = solution.Value(routing.NextVar(index))
route_distance += routing.GetArcCostForVehicle(previous_index, index, 0)
plan_output += f" {manager.IndexToNode(index)}\n"
plan_output += f"Route distance: {route_distance} miles\n"
print(plan_output)
def main():
"""Entry point of the program."""
# Instantiate the data problem.
data = create_data_model()
# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(
len(data["distance_matrix"]), data["num_vehicles"], data["depot"]
)
# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)
def distance_callback(from_index, to_index):
"""Returns the distance between the two nodes."""
# Convert from routing variable Index to distance matrix NodeIndex.
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return data["distance_matrix"][from_node][to_node]
transit_callback_index = routing.RegisterTransitCallback(distance_callback)
# Define cost of each arc.
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
# Setting first solution heuristic.
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC
)
# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)
# Print solution on console.
if solution:
print_solution(manager, routing, solution)
if __name__ == "__main__":
main()

10
Assignment2/B/data.lp Normal file
View File

@ -0,0 +1,10 @@
task(0, 2).
task(1, 3).
task(2, 1).
task(3, 9).
task(4, 2).
task(5, 8).
task(6, 9).
task(7, 8).
task(8, 5).
task(9, 8).

1
Assignment2/B/data.py Normal file
View File

@ -0,0 +1 @@
[2, 3, 1, 9, 2, 8, 9, 8, 5, 8]

10
Assignment2/B/data10.lp Normal file
View File

@ -0,0 +1,10 @@
task(0, 4).
task(1, 1).
task(2, 3).
task(3, 9).
task(4, 10).
task(5, 7).
task(6, 5).
task(7, 10).
task(8, 1).
task(9, 3).

1
Assignment2/B/data10.py Normal file
View File

@ -0,0 +1 @@
[4, 1, 3, 9, 10, 7, 5, 10, 1, 3]

20
Assignment2/B/data20.lp Normal file
View File

@ -0,0 +1,20 @@
task(0, 7).
task(1, 6).
task(2, 2).
task(3, 17).
task(4, 10).
task(5, 19).
task(6, 20).
task(7, 17).
task(8, 1).
task(9, 12).
task(10, 17).
task(11, 6).
task(12, 5).
task(13, 7).
task(14, 20).
task(15, 17).
task(16, 2).
task(17, 3).
task(18, 19).
task(19, 11).

1
Assignment2/B/data20.py Normal file
View File

@ -0,0 +1 @@
[7, 6, 2, 17, 10, 19, 20, 17, 1, 12, 17, 6, 5, 7, 20, 17, 2, 3, 19, 11]

30
Assignment2/B/data30.lp Normal file
View File

@ -0,0 +1,30 @@
task(0, 1).
task(1, 19).
task(2, 21).
task(3, 8).
task(4, 6).
task(5, 24).
task(6, 17).
task(7, 23).
task(8, 15).
task(9, 22).
task(10, 14).
task(11, 2).
task(12, 2).
task(13, 10).
task(14, 3).
task(15, 17).
task(16, 17).
task(17, 19).
task(18, 26).
task(19, 9).
task(20, 28).
task(21, 16).
task(22, 22).
task(23, 19).
task(24, 17).
task(25, 15).
task(26, 18).
task(27, 15).
task(28, 23).
task(29, 27).

1
Assignment2/B/data30.py Normal file
View File

@ -0,0 +1 @@
[1, 19, 21, 8, 6, 24, 17, 23, 15, 22, 14, 2, 2, 10, 3, 17, 17, 19, 26, 9, 28, 16, 22, 19, 17, 15, 18, 15, 23, 27]

View File

@ -0,0 +1,15 @@
import random
import sys
if len(sys.argv) == 2: x = int(sys.argv[1])
else: x = 10
file1 = open("data" + str(x) + ".lp", "w")
file2 = open("data" + str(x) + ".py", "w")
file2.write('[')
for i in range(x):
j = random.randint(1,x)
file1.write("task({}, {}).\n".format(i, j))
file2.write(str(j))
if i != x - 1: file2.write(", ")
file2.write(']')
file1.close()
file2.close()

16
Assignment2/B/task.lp Normal file
View File

@ -0,0 +1,16 @@
% Input facts
#const deadline = 90.
#const processors = 8.
#include "data30.lp".
1 { start(T, Time) : Time = 0..deadline } 1 :- task(T, _).
1 { end(T, Time) : Time = 0..deadline } 1 :- task(T, _).
:- start(T, Time), end(T, End), task(T, Length), End != Time + Length.
:- Time = 0..deadline, not #count{ T : start(T, StartTime), end(T, EndTime), StartTime <= Time, Time < EndTime } <= processors.
:- task(T, _), end(T, Time), Time > deadline.
#show start/2.
#show end/2.

50
Assignment2/B/task.py Normal file
View File

@ -0,0 +1,50 @@
"""Solves a simple assignment problem."""
from ortools.sat.python import cp_model
def main() -> None:
# Data
costs = [10,5,8,10,5,2,1]
num_workers = 2
deadline = 20
num_tasks = len(costs)
# Model
model = cp_model.CpModel()
# Variables
x = {}
for worker in range(num_workers):
for task in range(num_tasks):
x[worker, task] = model.new_bool_var(f"x[{worker},{task}]")
# Each task is assigned to exactly one worker.
for task in range(num_tasks):
model.add_exactly_one(x[worker, task] for worker in range(num_workers))
# Objective
for worker in range(num_workers):
objective_terms = []
for task in range(num_tasks):
objective_terms.append(costs[task] * x[worker, task])
model.AddLinearConstraint(sum(objective_terms), 0, deadline)
# Solve
solver = cp_model.CpSolver()
status = solver.solve(model)
# Print solution.
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
print(f"Total cost = {solver.objective_value}\n")
for worker in range(num_workers):
for task in range(num_tasks):
if solver.boolean_value(x[worker, task]):
print(
f"Worker {worker} assigned to task {task}."
+ f" Cost = {costs[task]}"
)
else:
print("No solution found.")
if __name__ == "__main__":
main()

13
Assignment2/C/cut.dat Normal file
View File

@ -0,0 +1,13 @@
param: WIDTHS: orders:=
6.77 10
7.56 40
17.46 33
18.76 10 ;
param nPAT := 9 ;
param nbr: 1 2 3 4 5 6 7 8 9 :=
6.77 0 1 1 0 3 2 0 1 4
7.56 1 0 2 1 1 4 6 5 2
17.46 0 1 0 2 1 0 1 1 1
18.76 3 2 2 1 1 1 0 0 0 ;

66
Assignment2/C/cut.lp Normal file
View File

@ -0,0 +1,66 @@
#const max = 10.
#const size = 30.
order(1, size).
order(2, size).
order(3, size).
order(4, size).
width(1).
width(2).
width(3).
width(4).
pattern(1, 1, 0).
pattern(1, 2, 1).
pattern(1, 3, 0).
pattern(1, 4, 3).
pattern(2, 1, 1).
pattern(2, 2, 0).
pattern(2, 3, 1).
pattern(2, 4, 2).
pattern(3, 1, 1).
pattern(3, 2, 2).
pattern(3, 3, 0).
pattern(3, 4, 2).
pattern(4, 1, 0).
pattern(4, 2, 1).
pattern(4, 3, 2).
pattern(4, 4, 1).
pattern(5, 1, 3).
pattern(5, 2, 1).
pattern(5, 3, 1).
pattern(5, 4, 1).
pattern(6, 1, 2).
pattern(6, 2, 4).
pattern(6, 3, 0).
pattern(6, 4, 1).
pattern(7, 1, 0).
pattern(7, 2, 6).
pattern(7, 3, 1).
pattern(7, 4, 0).
pattern(8, 1, 1).
pattern(8, 2, 5).
pattern(8, 3, 1).
pattern(8, 4, 0).
pattern(9, 1, 4).
pattern(9, 2, 2).
pattern(9, 3, 1).
pattern(9, 4, 0).
1 { cut(I, 0..max) } 1:- pattern(I, _, _).
:- order(W, L), #sum { J * K: pattern(I, W, J), cut(I, K)} < L.
total(N) :- N = #sum {J, I : cut(I, J)}.
#minimize {N: total(N)}.
#show cut/2.
#show total/1.

20
Assignment2/C/cut.mod Normal file
View File

@ -0,0 +1,20 @@
set WIDTHS;
param orders {WIDTHS} > 0;
param nPAT integer >= 0;
param nbr {WIDTHS, 1..nPAT} integer >= 0;
var Cut {1..nPAT} integer >= 0;
minimize Number:
sum {j in 1..nPAT} Cut[j];
subject to Fulfill {i in WIDTHS}:
sum {j in 1..nPAT} nbr[i,j] * Cut[j] >= orders[i];
data cut.dat;
option solver cplex;
solve;
option omit_zero_rows 1;
option display_1col 0;
display Cut;

36
Assignment2/README.md Normal file
View File

@ -0,0 +1,36 @@
# Assignment 1
## Part A
### clingo
## Part B
### clingo
| size | processors | deadline | result | time |
| ---- | ---------- | -------- |
| 10 | 3 | 20 | yes | 0.031 |
| 20 | 6 | 30 | no | 4.498 |
| 20 | 8 | 30 | yes | 0.233 |
| 30 | 6 | 60 | unknown | too long to solve |
| 30 | 8 | 60 | yes | 2.961 |
| 30 | 8 | 80 | yes | 6.701 |
| 30 | 8 | 90 | yes | 9.245 |
With either too high or too low constrain, the runtime grows exponentially. If the constrain is too low, it must iterate through all answers to find one correct result. If it is too high, then it may waste too much time fill the first processor.
### Google OR-Tools
## Part C
### clingo
| size | ans | time |
| ---- | --- | ------ |
| 5 | 5 | 0.678 |
| 10 | 9 | 0.866 |
| 15 | 13 | 1.122 |
| 20 | 17 | 1.902 |
| 25 | 21 | 6.379 |
| 30 | 25 | 34.466 |
One important factor of the runtime is the max number of cut to check. If we set max = 10 with size = 30, we get the time of 0.914. However, it is impossible to get the max size before running, I believe this time would be a great representation of the runtime of clingo.
### AMPL