AMPL Christmas Model created by ChatGPT

christmas.ipynb Open In Colab Kaggle Gradient Open In SageMaker Studio Lab Hits

Description: Christmas model generated by ChatGPT

Tags: christmas, chatgpt, amplpy, highlights

Notebook author: Filipe Brandão <fdabrandao@gmail.com>

Model author: ChatGPT

# Install dependencies
%pip install -q amplpy pandas
# Google Colab & Kaggle integration
from amplpy import AMPL, ampl_notebook

ampl = ampl_notebook(
    modules=["highs", "cbc", "gurobi"],  # modules to install
    license_uuid="default",  # license to use
)  # instantiate AMPL object and register magics

ChatGPT & AMPL

The AMPL dev team spent some time this week asking ChatGPT to write AMPL models. Sometimes the responses were not perfect, which is to be expected, but we would work WITH ChatGPT on lines of code that were incorrect and it LEARNED from its errors, corrected the model and provided us with an updated version.

Social media posts with video: LinkedIn Post | Twitter Post | YouTube Video

Christmas model by ChatGPT

Problem description, mathematical model, AMPL model and data copied directly from ChatGPT:

AMPL Model

MathJax description

In this optimization problem, we are trying to choose the best gift for each person, given a set of people PEOPLE and a set of gifts GIFTS, in order to maximize the total happiness. Each gift has a certain cost, and we have a budget that we cannot exceed. Each person can only receive one gift. The decision variables x[p,g] represent whether each person p receives each gift g, and must be binary (either 0 or 1).

The mathematical formulation of the problem is as follows:

$$ \begin{aligned} \text{maximize} \quad &\sum_{p \in \text{PEOPLE}} \sum_{g \in \text{GIFTS}} \text{happiness}{p,g} \cdot x{p,g} \ \text{subject to} \quad &\sum_{p \in \text{PEOPLE}} \sum_{g \in \text{GIFTS}} \text{cost}g \cdot x{p,g} \le \text{budget} \ &\sum_{g \in \text{GIFTS}} x_{p,g} = 1 \quad \forall p \in \text{PEOPLE} \ &x_{p,g} \in {0,1} \quad \forall p \in \text{PEOPLE}, g \in \text{GIFTS} \end{aligned} $$

%%ampl_eval
reset; # clear previous definitions
# define the set of people
set PEOPLE;

# define the set of gifts
set GIFTS;

# define the cost of each gift
param cost{GIFTS};

# define the happiness level for each person receiving each gift
param happiness{PEOPLE, GIFTS};

# define the budget for gift-giving
param budget;

# define the decision variables:
# x[p,g] is 1 if person p receives gift g, 0 otherwise
var x{PEOPLE, GIFTS} binary;

# the objective is to maximize total happiness
maximize total_happiness: sum{p in PEOPLE, g in GIFTS} happiness[p,g] * x[p,g];

# subject to the budget constraint:
# the total cost of the gifts must be less than or equal to the budget
subject to budget_constraint: sum{p in PEOPLE, g in GIFTS} cost[g] * x[p,g] <= budget;

# each person can only receive one gift
subject to one_gift_per_person{p in PEOPLE}: sum{g in GIFTS} x[p,g] = 1;

Load data directly from python data structures using amplpy

ampl.set["PEOPLE"] = ["Alice", "Bob", "Carol", "Dave", "Eve"]
ampl.set["GIFTS"] = ["Book", "Toy", "Chocolate", "Wine", "Flowers"]
ampl.param["cost"] = {"Book": 10, "Toy": 20, "Chocolate": 5, "Wine": 15, "Flowers": 7}
ampl.param["budget"] = 50
import pandas as pd

happiness_df = pd.DataFrame(
    {
        "Book": [3, 2, 5, 1, 4],
        "Toy": [5, 2, 4, 3, 1],
        "Chocolate": [1, 3, 4, 5, 2],
        "Wine": [2, 5, 3, 4, 1],
        "Flowers": [4, 3, 1, 2, 5],
    },
    index=["Alice", "Bob", "Carol", "Dave", "Eve"],
)

display(happiness_df)  # display 2D Pandas DataFrame
Book Toy Chocolate Wine Flowers
Alice 3 5 1 2 4
Bob 2 2 3 5 3
Carol 5 4 4 3 1
Dave 1 3 5 4 2
Eve 4 1 2 1 5
happiness_df_stacked = happiness_df.stack().to_frame()
display(happiness_df_stacked)  # display Pandas DataFrame with Multi-Index
0
Alice Book 3
Toy 5
Chocolate 1
Wine 2
Flowers 4
Bob Book 2
Toy 2
Chocolate 3
Wine 5
Flowers 3
Carol Book 5
Toy 4
Chocolate 4
Wine 3
Flowers 1
Dave Book 1
Toy 3
Chocolate 5
Wine 4
Flowers 2
Eve Book 4
Toy 1
Chocolate 2
Wine 1
Flowers 5
# To load the data for the parameter happiness you can use either happiness_df or happiness_df_stacked in the same way
ampl.param["happiness"] = happiness_df

Solve with HiGHS and retrieve solution

ampl.option["solver"] = "highs"
ampl.solve()

solution = ampl.get_data("{p in PEOPLE, g in GIFTS: x[p, g] > 0} x[p, g]").to_dict()
print(f"Solution:\n\t{solution}")

print("\nTo maximize the total happiness:")
for person, gift in solution:
    print(f"- give {gift} to {person}.")
HiGHS 1.6.0: HiGHS 1.6.0: optimal solution; objective 24
3 simplex iterations
1 branching nodes
 
Solution:
	{('Alice', 'Flowers'): 1, ('Bob', 'Wine'): 1, ('Carol', 'Book'): 1, ('Dave', 'Chocolate'): 1, ('Eve', 'Flowers'): 1}

To maximize the total happiness:
- give Flowers to Alice.
- give Wine to Bob.
- give Book to Carol.
- give Chocolate to Dave.
- give Flowers to Eve.

Change the budget and solve with Gurobi

ampl.param["budget"] = 100
ampl.option["solver"] = "gurobi"
ampl.solve()

solution = ampl.var["x"].to_pandas()  # retrieve variable values as a Pandas DataFrame
print("Solution:")
display(solution[solution["x.val"] == 1])  # display rows with x.val == 1

print("\nTo maximize the total happiness:")
for person, gift in solution.index[solution["x.val"] == 1].tolist():
    print(f"- give {gift} to {person}.")
Gurobi 11.0.0: Gurobi 11.0.0: optimal solution; objective 25
0 simplex iterations
 
Solution:
x.val
index0 index1
Alice Toy 1
Bob Wine 1
Carol Book 1
Dave Chocolate 1
Eve Flowers 1
To maximize the total happiness:
- give Toy to Alice.
- give Wine to Bob.
- give Book to Carol.
- give Chocolate to Dave.
- give Flowers to Eve.

Change the budget once again and solve with CBC

ampl.param["budget"] = 30
ampl.option["solver"] = "cbc"
ampl.solve()

solution = ampl.var["x"].to_dict()  # retrieve variable values as a dictionary
print(f"Solution:\n\t{solution}")

print("\nTo maximize the total happiness:")
for person, gift in solution:
    if solution[person, gift] == 1:
        print(f"- give {gift} to {person}.")
cbc 2.10.10: cbc 2.10.10: optimal solution; objective 21
0 simplex iterations
 
Solution:
	{('Alice', 'Book'): 0, ('Alice', 'Chocolate'): 0, ('Alice', 'Flowers'): 1, ('Alice', 'Toy'): 0, ('Alice', 'Wine'): 0, ('Bob', 'Book'): 0, ('Bob', 'Chocolate'): 1, ('Bob', 'Flowers'): 0, ('Bob', 'Toy'): 0, ('Bob', 'Wine'): 0, ('Carol', 'Book'): 0, ('Carol', 'Chocolate'): 1, ('Carol', 'Flowers'): 0, ('Carol', 'Toy'): 0, ('Carol', 'Wine'): 0, ('Dave', 'Book'): 0, ('Dave', 'Chocolate'): 1, ('Dave', 'Flowers'): 0, ('Dave', 'Toy'): 0, ('Dave', 'Wine'): 0, ('Eve', 'Book'): 0, ('Eve', 'Chocolate'): 0, ('Eve', 'Flowers'): 1, ('Eve', 'Toy'): 0, ('Eve', 'Wine'): 0}

To maximize the total happiness:
- give Flowers to Alice.
- give Chocolate to Bob.
- give Chocolate to Carol.
- give Chocolate to Dave.
- give Flowers to Eve.

Some useful information:

  • You can see more models at the AMPL Model Colaboratory: https://colab.ampl.com

  • You can ask for help at the AMPL Discourse Forum: https://discuss.ampl.com

  • You can get a free AMPL Community Edition license: https://ampl.com/ce/