#do not forget to instal pulp
#python -m pip install pulp

import gurobipy as gp
from gurobipy import GRB

# ---------------------------
# DATA (same structure as PuLP)
# ---------------------------
m = 4  # number of constraints
n = 2  # number of variables

indexI = range(1, m + 1)
indexJ = range(1, n + 1)

A = {
    1: {1: 6, 2: 4},
    2: {1: 1, 2: 2},
    3: {1: -1, 2: 1},
    4: {1: 0, 2: 1},
}

B = {1: 24, 2: 6, 3: 1, 4: 2}
C = {1: 5, 2: 4}

# ---------------------------
# Model Definition
# ---------------------------
model = gp.Model("ReddyMikks")

# Variables x[j] ≥ 0
x = {j: model.addVar(lb=0, name=f"x_{j}") for j in indexJ}

# Objective Function: Maximize sum(C[j] * x[j])
model.setObjective(
    gp.quicksum(C[j] * x[j] for j in indexJ),
    GRB.MAXIMIZE
)

# Constraints: sum(A[i][j] * x[j]) ≤ B[i]
constraints = {}
for i in indexI:
    constraints[i] = model.addConstr(
        gp.quicksum(A[i][j] * x[j] for j in indexJ) <= B[i],
        name=f"constraint_{i}"
    )
# ---------------------------
# Solve the Model
# ---------------------------
model.optimize()

# ---------------------------
# Print Results
# ---------------------------

# Status
print("\nOptimization Status:", model.Status)
if model.Status == GRB.OPTIMAL:
    print("\n✅ Optimal solution found!")

    # Objective value
    print(f"\nObjective Function Value: {model.ObjVal:.2f}")

    # Variable values
    print("\nVariable Values:")
    for j in indexJ:
        print(f"  x_{j} = {x[j].X:.2f}")

    # Slack and shadow prices
    print("\nConstraint Info:")
    for i in indexI:
        c = constraints[i]
        print(f"  constraint_{i}: Slack = {c.Slack:.2f}, Shadow Price = {c.Pi:.2f}")

    # Sensitivity: Objective coefficient ranges
    print("\nSensitivity Analysis - Objective Coefficient Ranges:")
    for j in indexJ:
        var = x[j]
        print(f"  x_{j}: Coeff = {C[j]}, Reduced Cost = {var.RC:.2f}, "
              f"Allowable Range = [{var.SAObjLow:.2f}, {var.SAObjUp:.2f}]")

    # Sensitivity: RHS ranges
    print("\nSensitivity Analysis - RHS Ranges:")
    for i in indexI:
        c = constraints[i]
        low = "-∞" if c.SARHSLow <= -GRB.INFINITY else f"{c.SARHSLow:.2f}"
        up = "+∞" if c.SARHSUp >= GRB.INFINITY else f"{c.SARHSUp:.2f}"
        print(f"  constraint_{i}: RHS = {B[i]}, Shadow Price = {c.Pi:.2f}, "
              f"Allowable RHS Range = [{low}, {up}]")
else:
    print("⚠️ No optimal solution found.")
