A container shipping company needs to execute a transport contract from Shanghai to Los Angeles, a total sailing distance of 6000 nautical miles. The voyage must be completed within 12 days (288 hours). The company can choose one of three different types of vessels from its fleet to carry out this mission. The fuel consumption rate for each vessel is an approximate quadratic function of its sailing speed v. The price of fuel is ¥4000 per ton. Additionally, due to new environmental regulations, the company must pay for its carbon dioxide emissions at a rate of ¥300 per ton of CO2. Specific information for the three vessels is shown in Table 1, including their fuel consumption formulas, CO2 emission factors, and a fixed cost for selecting each vessel.

Table 1: Vessel Information 

| Vessel | Fuel Consumption (tons/hour) | CO2 Emission Factor (ton CO2/ton fuel) | Selection Fixed Cost (¥) |
|------|----------------------------------|------|---------|
| Ship A | $0.005 \times v^2 + 0.1v + 1.2$  | 3.2  | 500,000 |
| Ship B | $0.004 \times v^2 + 0.08v + 1.5$ | 3.15 | 600,000 |
| Ship C | $0.006 \times v^2 + 0.12v + 1.0$ | 3.25 | 450,000 |

The objective is to select one vessel and determine its optimal sailing speed to minimize the total cost of the voyage.

Problem type: NLP (Small: 9 variables, 7 constraints, 15 nonzeros)

Mathematical model:
Set:
1.  Vessel 
The set of available vessels, \( S = \{1, 2, 3\} \) # 1: Ship A, 2: Ship B, 3: Ship C

Parameter:
1.  Distance
The total sailing distance.  
    6000 # in nautical miles
2.  MaxTime
The maximum allowed time for the voyage.  
    288 # in hours
3.  FuelPrice
The cost of fuel.  
    4000 # in ¥ per ton
4.  CarbonTax
The tax on CO2 emissions.  
    300 # in ¥ per ton of CO2
5.  FuelCoeffs
The coefficients \([a, b, c]\) for the fuel consumption formula \(a \times v^2 + b \times v + c\).  
    [[0.005, 0.1, 1.2], [0.004, 0.08, 1.5], [0.006, 0.12, 1.0]]
6.  CO2Factor
The CO2 emission factor for each vessel.  
    [3.2, 3.15, 3.25] # in tons of CO2 per ton of fuel
7.  FixedCost
The fixed cost for selecting each vessel.  
    [500000, 600000, 450000] # in ¥

Decision variable:
1.  SelectVessel
Binary variable, \( y[s] \forall s \in S \), which is 1 if vessel \(s\) is selected, and 0 otherwise.
2.  SailingSpeed
Continuous variable, \( v \), representing the sailing speed in knots.

Objective:
1.  Minimize the total cost.
The objective is to minimize the sum of the selected vessel's fixed cost, fuel cost, and carbon cost. The fuel and carbon costs are functions of the sailing speed \( v \).  
    min: \( \sum_{s \in S} y[s] \times \bigg( FixedCost[s] + (FuelPrice + CarbonTax \times CO2Factor[s]) \times Distance \times (FuelCoeffs[s][0] \times v + FuelCoeffs[s][1] + \frac{FuelCoeffs[s][2]}{v}) \bigg) \)

Constraint:
1. Vessel Selection Constraint
Exactly one vessel must be selected for the mission.  
    \( \sum_{s \in S} y[s] = 1 \)
2. Time Constraint
The total voyage time must not exceed the maximum allowed time. This imposes a minimum required speed.  
    \( v \geq \frac{Distance}{MaxTime} \)
3. Variable Type Constraints
\( y[s] \in \{0, 1\} \forall s \in S \)  
    \( v > 0 \)

Type:
Mixed, Non-linear, Linear  
NLP

Gurobi implementation:
import gurobipy as gp
from gurobipy import GRB


def solve_shipping_minlp_robust(
    vessels=["Ship_A", "Ship_B", "Ship_C"],
    distance=6000.0,
    max_time=288.0,
    fuel_price=4000.0,
    carbon_tax=300.0,
    max_speed=30.0,
    fixed_cost={
        "Ship_A": 500000,
        "Ship_B": 600000,
        "Ship_C": 450000
    },
    co2_factor={
        "Ship_A": 3.2,
        "Ship_B": 3.15,
        "Ship_C": 3.25
    },
    fuel_coeffs={
        "Ship_A": {"a": 0.005, "b": 0.1, "c": 1.2},
        "Ship_B": {"a": 0.004, "b": 0.08, "c": 1.5},
        "Ship_C": {"a": 0.006, "b": 0.12, "c": 1.0}
    }
):
    """
    Solves the vessel selection and speed optimization problem using a robust
    MIQCP (Mixed-Integer Quadratically Constrained Programming) formulation.
    """
    # Create a new model
    model = gp.Model("ShippingOptimization_Robust")

    # --- Decision Variables ---
    # 1. Binary variable to select exactly one vessel
    select_vessel = model.addVars(vessels, vtype=GRB.BINARY, name="SelectVessel")

    # 2. Continuous variable for the speed of EACH vessel
    speed_per_vessel = model.addVars(vessels, lb=0.0, ub=max_speed, name="Speed")

    # 3. Auxiliary variable z_s = y_s / v_s
    aux_z = model.addVars(vessels, lb=0.0, name="Aux_Z")

    # --- Constraints ---
    # 1. Vessel Selection Constraint: Exactly one vessel must be chosen
    model.addConstr(select_vessel.sum('*') == 1, name="OneVesselMustBeSelected")

    # 2. Link speed to vessel selection
    min_speed = distance / max_time
    for s in vessels:
        # The speed v_s must be >= min_speed if vessel s is selected (y_s=1)
        model.addConstr(speed_per_vessel[s] >= min_speed * select_vessel[s], name=f"MinSpeed_{s}")
        # The speed v_s must be <= max_speed if vessel s is selected (y_s=1)
        model.addConstr(speed_per_vessel[s] <= max_speed * select_vessel[s], name=f"MaxSpeed_{s}")

        # 3. Core non-convex quadratic constraint: z_s * v_s = y_s
        model.addQConstr(aux_z[s] * speed_per_vessel[s] == select_vessel[s], name=f"AuxConstraint_{s}")

    # --- Objective Function: Minimize Total Cost ---
    # Total Fixed Cost
    total_fixed_cost = select_vessel.prod(fixed_cost)

    # Total Variable Cost (Fuel + Carbon)
    # The original variable cost per ship was C_var * D * (a*v + b + c/v)
    # With our auxiliary variables, this becomes:
    # C_var * D * (a*v_s + b*y_s + c*z_s)
    total_variable_cost = gp.quicksum(
        (fuel_price + carbon_tax * co2_factor[s]) * distance * (
            fuel_coeffs[s]['a'] * speed_per_vessel[s] +
            fuel_coeffs[s]['b'] * select_vessel[s] +
            fuel_coeffs[s]['c'] * aux_z[s]
        ) for s in vessels
    )

    model.setObjective(total_fixed_cost + total_variable_cost, GRB.MINIMIZE)

    # --- Gurobi Settings for Non-Convex Problems ---
    model.Params.NonConvex = 2

    # Optimize the model
    model.optimize()

    # --- Return Results ---
    if model.status == GRB.OPTIMAL:
        return {"status": "optimal", "obj": model.objVal}
    else:
        return {"status": f"{model.status}"}


# Run the solver function
if __name__ == '__main__':
    result = solve_shipping_minlp_robust()
    print(result)

Solution status: OPTIMAL
Optimal objective value: 7582340