You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于CPLEX的化工厂反应器扩容决策建模技术咨询

Adding Reactor Investment Decision to Your CPLEX Chemical Plant Model

Got it, let's break down how to integrate the reactor investment decision into your existing model. The core challenge is linking the "add/no-add + model choice" decision to dependent factors like initial stock, reactor capacity constraints, and net profit (accounting for reactor costs). Here's a step-by-step implementation:


1. Add Decision Variables for Reactor Selection

First, define variables to represent your choice: no new reactor, or one of the three models. We'll use boolean variables to enforce exactly one option is selected.

// Define reactor options: 0 = no new reactor, 1/2/3 = three different models
{int} ReactorOptions = {0, 1, 2, 3};
dvar boolean ChooseReactor[m in ReactorOptions];

// Constraint: Must select exactly one option (no reactor or one model)
subject to {
    sum(m in ReactorOptions) ChooseReactor[m] == 1;
}

Your initial stock depends on how many reactors are running. First, compute the total number of reactors, then define initial stock as a function of your selection.

// Total reactors: original 3 + 1 if we choose any model (0 adds 0)
dexpr int TotalReactors = 3 + sum(m in ReactorOptions: m != 0) ChooseReactor[m];

// Define initial stock values per scenario:
// - InitialStock_3: stock when using original 3 reactors
// - InitialStock_1/2/3: stock when adding model 1/2/3
int InitialStock_3[Resources] = ...; // Your original initial stock values
int InitialStock_1[Resources] = ...; // Stock for model 1 addition
int InitialStock_2[Resources] = ...; // Stock for model 2 addition
int InitialStock_3_new[Resources] = ...; // Stock for model 3 addition

// Dynamic initial stock based on reactor choice
dexpr int InitialStock[r in Resources] = 
    InitialStock_3[r] * ChooseReactor[0] +
    InitialStock_1[r] * ChooseReactor[1] +
    InitialStock_2[r] * ChooseReactor[2] +
    InitialStock_3_new[r] * ChooseReactor[3];

3. Update Objective Function to Account for Reactor Costs

Your goal is still maximizing net profit, so subtract the cost of the selected reactor from your original profit calculation.

// Cost of each reactor option: 0 = no cost for no reactor
float ReactorCost[m in ReactorOptions] = [0, cost_model1, cost_model2, cost_model3];

// Updated objective: original profit minus reactor cost
dexpr float ObjFunction = 
    sum(r in nrenuableR) (R[r][MaxTime] - InitialStock[r]) * (Profit[r] - nRcosts[r])
    - sum(m in ReactorOptions) ReactorCost[m] * ChooseReactor[m];
maximize ObjFunction;

4. Fix Reactor Scheduling Constraints

You mentioned each reactor can only do one task at a time—your original model was missing this critical constraint. We'll add assignment variables to link tasks to reactors, and enforce exclusivity based on the total number of active reactors.

// Max possible reactors is 4 (original 3 + 1 new one)
range Reactors = 1..4;
// Assign[k][t][s] = 1 if task k starts at time t on reactor s
dvar boolean Assign[k in Tasks][t in Time][s in Reactors];
// ReactorActive[s] = 1 if reactor s is in use (depends on TotalReactors)
dvar boolean ReactorActive[s in Reactors];

// Enforce total active reactors matches our selection
subject to {
    sum(s in Reactors) ReactorActive[s] == TotalReactors;
}

// Tasks can only be assigned to active reactors
forall(k in Tasks, t in Time, s in Reactors) {
    Assign[k][t][s] <= ReactorActive[s];
}

// A reactor can't run more than one task at the same time
forall(s in Reactors, t in Time) {
    sum(k in Tasks) Assign[k][t][s] <= 1;
}

// If a task starts at time t (N[k][t] = 1), it must be assigned to a reactor
forall(k in Tasks, t in Time) {
    N[k][t] <= sum(s in Reactors) Assign[k][t][s];
}

// Prevent overlapping tasks on the same reactor (account for process time)
forall(k in Tasks, t in Time, s in Reactors) {
    forall(tp in t..min(t + procTime[k] - 1, MaxTime)) {
        Assign[k][t][s] <= 1 - sum(k2 in Tasks: k2 != k) Assign[k2][tp][s];
    }
}

Full Modified Code

Here's how all the pieces fit together (integrated with your original code):

// Data declaration
int MaxTime = ...;
range Time = 0..MaxTime;
{int} Tasks = ...;
{string} nrenuableR=...;
{string} renuableR=...;
{string} renuableRusedbyT[Tasks]=...;
{string} Resources= nrenuableR union renuableR;
int procTime[Tasks]= ...;
int minbatchsize[renuableR][Tasks] =...;
int maxbatchsize [renuableR][Tasks] =...;
int MaxAmountStock_nR[nrenuableR]=...;
int maxRenuableR[renuableR][Time] =...;
int Profit[nrenuableR]=...;
float nRcosts[nrenuableR]=...;
int MaxTheta = ...;
range Theta=0..MaxTheta;
float Mu[Tasks][Resources][Theta] = ...;
float Nu[Tasks][Resources][Theta] = ...;

// Reactor investment data
{int} ReactorOptions = {0, 1, 2, 3};
float ReactorCost[m in ReactorOptions] = [0, cost_model1, cost_model2, cost_model3];
int InitialStock_3[Resources] = ...; // Original 3 reactors stock
int InitialStock_1[Resources] = ...; // Stock with model 1 added
int InitialStock_2[Resources] = ...; // Stock with model 2 added
int InitialStock_3_new[Resources] = ...; // Stock with model 3 added

// Decision variables
dvar boolean N[Tasks][Time];
dvar float+ Csi[Tasks][Time];
dvar int+ R[Resources][Time];
dvar boolean ChooseReactor[m in ReactorOptions];
range Reactors = 1..4;
dvar boolean Assign[k in Tasks][t in Time][s in Reactors];
dvar boolean ReactorActive[s in Reactors];

// Derived expressions
dexpr int TotalReactors = 3 + sum(m in ReactorOptions: m != 0) ChooseReactor[m];
dexpr int InitialStock[r in Resources] = 
    InitialStock_3[r] * ChooseReactor[0] +
    InitialStock_1[r] * ChooseReactor[1] +
    InitialStock_2[r] * ChooseReactor[2] +
    InitialStock_3_new[r] * ChooseReactor[3];

// Objective function
dexpr float ObjFunction = 
    sum(r in nrenuableR) (R[r][MaxTime] - InitialStock[r]) * (Profit[r] - nRcosts[r])
    - sum(m in ReactorOptions) ReactorCost[m] * ChooseReactor[m];
maximize ObjFunction;

// Constraint conditions
subject to {
    // Reactor selection constraint
    sum(m in ReactorOptions) ChooseReactor[m] == 1;
    
    // Reactor activation count constraint
    sum(s in Reactors) ReactorActive[s] == TotalReactors;
    
    // Resource capacity constraints
    forall (r in renuableR) forall(t in Time) R[r][t] <= maxRenuableR[r][t];
    forall (r in nrenuableR) forall (t in Time) R[r][t] <= MaxAmountStock_nR[r];
    
    // Batch size constraints
    forall (k in Tasks, r in renuableRusedbyT[k], t in Time) minbatchsize[r][k] * N[k][t] <= Csi[k][t];
    forall (k in Tasks, r in renuableRusedbyT[k], t in Time) maxbatchsize[r][k]*N[k][t] >= Csi[k][t];
    
    // Resource balance constraints
    forall(r in Resources) R[r][0] == InitialStock[r] + sum(k in Tasks) (Mu[k][r][0] * N[k][0] + Nu[k][r][0] * Csi[k][0]);
    forall(r in Resources,t in Time: t>0) R[r][t] == R[r][t-1] + sum(k in Tasks,theta in Theta: t - theta >=0) (Mu[k][r][theta] * N[k][t - theta] + Nu[k][r][theta] * Csi[k][t - theta]);
    
    // Reactor assignment constraints
    forall(k in Tasks, t in Time, s in Reactors) {
        Assign[k][t][s] <= ReactorActive[s];
    }
    forall(s in Reactors, t in Time) {
        sum(k in Tasks) Assign[k][t][s] <= 1;
    }
    forall(k in Tasks, t in Time) {
        N[k][t] <= sum(s in Reactors) Assign[k][t][s];
    }
    forall(k in Tasks, t in Time, s in Reactors) {
        forall(tp in t..min(t + procTime[k] - 1, MaxTime)) {
            Assign[k][t][s] <= 1 - sum(k2 in Tasks: k2 != k) Assign[k2][tp][s];
        }
    }
}

Key Notes

  • The ChooseReactor variables let CPLEX evaluate all four scenarios (no reactor + three models) and pick the one that maximizes net profit.
  • Dynamic initial stock ensures you're using the correct starting inventory for each reactor count scenario.
  • The reactor scheduling constraints enforce your "one task per reactor at a time" rule, even when the total number of reactors changes.
  • Subtracting reactor costs from the objective ensures you're comparing true net profit across all options.

内容的提问来源于stack exchange,提问作者Beatriz Estevens

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:58:05