Aidan Donnelly
Aidan Donnelly

Reputation: 389

In CVXPY, how to write a conditional constraint if X[i] > 0, then X[i] needs to be >= Y?

I have a convex optimisation problem with many different constraints that ensure level, running times etc. In this case assume N is 8.

See my problem written below:

N = len(periods_minutes)
        MIN_RUN_TIME = 25
        running_time = cp.Variable(N, integer=True)
        k = cp.Variable(N)
        mins = np.ones(N) * MIN_RUN_TIME
        maxs = np.ones(N) * periods_minutes

        print(mins)

        # Constant variables
        pump_flow = float(self.pump_data[len(self.pump_data)-1]["Flow"])
        pump_energy = float(self.pump_data[len(self.pump_data)-1]["Energy"])
        pump_flow_per_minute = pump_flow * 60

        # Optimiation calculations
        cost_of_running = cp.multiply((running_time/60), energy_costs * pump_energy)
        sum_of_energy = cp.sum(cost_of_running)
        volume_cp = cp.sum(running_time*pump_flow_per_minute)
        period_volume = running_time * pump_flow_per_minute

        # Reservoir information and calculations
        FACTOR = 1/self.SURFACE_AREA 
        flow_in = running_time * pump_flow_per_minute
        flow_diff = (flow_in - flow_out) / 1000
        res_level = cp.cumsum(flow_diff) * FACTOR + self.current_level

        # Constant constraints
        min_level_constraint = res_level >= self.min_level
        max_level_constraint = res_level <= self.max_level
        volume_constraint = volume_cp >= self.target
        # running_time_constraint = 0 == running_time >= 20

        # Build constraints
        constraints = []

        for i in range(N):
            constraints += [running_time[i] >= 0]
            constraints += [running_time[i] >= cp.multiply(k[i], mins)]
            constraints += [running_time[i] <= cp.multiply(k[i], maxs)]


        # Append common constraints
        constraints += [min_level_constraint]
        constraints += [max_level_constraint]
        constraints += [volume_constraint]
        # constraints += [running_time_constraint]
        

        # Objective definition
        objective = cp.Minimize(cp.sum(sum_of_energy))

        # Problem declaration
        prob = cp.Problem(objective, constraints)
        prob.solve(solver=cp.CPLEX, verbose=False)

I want to write a conditional statement like follows as a constraint:

if running_time[i] > 0:
    # Then it needs to be greater than a set value/variable
    running_time[i] >= Y || 20

I essentially need a minimum run time if we decide in the problem that running_time[i] is something like 4 or below 20, but we can allow it to be 0 if I have explained that correctly.

I have updated the question based on another answer and comments made below.

Upvotes: 0

Views: 1017

Answers (1)

Aidan Donnelly
Aidan Donnelly

Reputation: 389

Update: Thanks for everyone's comments and suggestions for the Cookbook and other Stack Overflow question I was able to implement the required constraints to satisfy my problem. See below for my updated code.

        N = len(periods_minutes)
        MIN_RUN_TIME = 20
        running_time = cp.Variable(N, integer=True)
        mins = np.ones(N) * MIN_RUN_TIME
        maxs = np.ones(N) * periods_minutes
        k = cp.Variable(N, boolean=True)

        # Constant variables
        pump_flow = float(self.pump_data[len(self.pump_data)-1]["Flow"])
        pump_energy = float(self.pump_data[len(self.pump_data)-1]["Energy"])
        pump_flow_per_minute = pump_flow * 60

        # Optimiation calculations
        running_time_hours = running_time / 60
        cost_of_running = cp.multiply(running_time_hours, energy_costs) * pump_energy
        sum_of_energy = cp.sum(cost_of_running)
        volume_cp = cp.sum(running_time*pump_flow_per_minute)
        period_volume = running_time * pump_flow_per_minute

        # Reservoir information and calculations
        FACTOR = 1/self.SURFACE_AREA 
        flow_in = running_time * pump_flow_per_minute
        flow_diff = (flow_in - flow_out) / 1000
        res_level = cp.cumsum(flow_diff) * FACTOR + self.current_level

        # Constant constraints
        min_level_constraint = res_level >= self.min_level
        max_level_constraint = res_level <= self.max_level
        volume_constraint = volume_cp >= self.target
        
        # Build constraints
        constraints = []

        # Append common constraints
        constraints += [min_level_constraint]
        constraints += [max_level_constraint]
        constraints += [volume_constraint]
        constraints += [running_time >= cp.multiply(k, mins)]
        constraints += [running_time <= cp.multiply(k, maxs)]        

        # Objective definition
        objective = cp.Minimize(cp.sum(sum_of_energy))

        # Problem declaration
        prob = cp.Problem(objective, constraints)
        prob.solve(solver=cp.CPLEX, verbose=False)

Upvotes: 1

Related Questions