[Python] Setting up a mixed-integer program in python

Discussão em 'Python' iniciado por Stack, Abril 27, 2025.

  1. Stack

    Stack Membro Participativo

    I am trying to figure out if it is possible to configure a specific problem as a mixed-integer program. I think I am able to structure it as a non-linear optimization problem, but would like to see if a MIP works better.

    The basic idea is that there are several systems comprised of multiple elements. Over time, the elements degrade and certain actions/decisions can be applied at periodic intervals. Each decision choice has a different cost and impact on element condition. The goal is to define the optimal set of decisions for each element at periodic intervals. However, the decisions must not allow an overall system to degrade below a minimally acceptable level, or to cost more than a budgeted amount for each period.

    Below is an example of how an example could be set up and how a single decision matrix would be evaluated:

    # 1. define parameters like # of systes, decision options, decision periods, types etc.
    # 2. define constraints
    # 3. model how the elements degrade over time, and costs for decisions
    # 4. model how elements will impact system metrics
    # 5. structure as MIP <- HOW TO DO THIS??:

    import random
    from random import choices
    import pandas as pd

    # define parameters
    #
    decision_options = list(range(0,4)) # defines number of decision options
    periods = list(range(0,6)) # defines number of decision periods
    system_types = ['A', 'B', 'C'] # type used for condition constraints

    # say we have 100 elements, each assigned to a system
    element_ids = list(range(0, 100))


    # create initialized element condition values
    condition = choices(range(60,101), k=len(element_ids))
    # assign types for each item
    system_type = choices(system_types, k=len(element_ids))
    # assign value for each group
    value = random.sample(range(500, 20000), len(element_ids))

    # create a dataframe with element, system type, condition, and element value information
    df = pd.DataFrame({'Element_ID': element_ids, 'System_Type': system_type, 'Condition': condition, "Value": value})
    df

    # 2. define constraints
    #
    # create a dict where each type has a minimum allowable condition
    vals= [60, 50, 40] # System = A has a limit of 60, System B has a limit of 50...
    min_condition = dict(zip(system_types, vals))

    # budget constraint for each period
    max_budget = [200000] * len(periods)

    # 3. model costs and degradation over time

    # create a function that sets a element cost based on decision
    def decision_cost(decision, value):
    cost = 0
    match decision:
    case 0:
    cost = 0 # do nothing
    case 1:
    cost = value / 10 # do a little
    case 2:
    cost = value / 5 # do a little more
    case 3:
    cost = value / 2 # do a lot
    return(cost)

    # create a function that sets a element condition based on decision
    def decision_result(decision, condition):

    match decision:
    case 0:
    condition = condition # no improvement
    case 1:
    condition = min(condition*1.1, 100) # a little improvement
    case 2:
    condition = min(condition*1.2, 100) # a little more improvement
    case 3:
    condition = min(condition*1.5, 100) # a lot of improvement
    return(condition)

    # model element degradation
    # element loses 10% at each period
    def degrade_element(condition):
    new_condition = round(condition *0.9,0)
    return(new_condition)

    # 4. model how elements will impact system metrics
    # these are to be compared to the min_condition constraints
    #
    # system condition is the weighted-and-summed condition of the constituent elements
    def system_condition(df):
    system_types = sorted(df['System_Type'].unique())
    system_condition = [0] * len(system_types)

    for i in range(len(system_types)):
    system_data = df[df['System_Type'] == system_types]
    system_condition = (system_data['Condition'] * system_data['Value']).sum() / system_data['Value'].sum()

    return(system_condition)

    def period_costs(new_df, periods):
    column_names = [f'Period_{p}' for p in periods]
    period_sums = []
    for col in column_names:
    period_sums.append(new_df[col].sum())
    return(period_sums)

    system_condition(df)

    # create a sample decision matrix:
    # row = element
    # column = period
    # cell value = decision

    import numpy as np

    # randomly initialize a decision matrix
    decision_matrix = np.random.randint(0, len(decision_options), size=(len(element_ids), max(periods)+1))

    # example evaluation of a decision matrix

    # get cost and result dataframes for system/element results
    system_cost_df = system_result_df = pd.DataFrame(index=range(len(system_types)), columns=range(0, len(periods)))
    element_cost_df = element_result_df = pd.DataFrame(index=range(len(element_ids)), columns=range(0, len(periods)))

    def evaluate_decision_matrix(df, decision_matrix, periods):
    new_df = df
    #new_df['Cost'] = 0
    # create a column to collect the cost for each period
    column_names = [f'Period_{p}' for p in periods]
    new_df = new_df.assign(**{col: 0 for col in column_names})
    # for each period
    for i in range(0, len(periods)):
    # for each element
    for j in range(0, len(element_ids)):
    # execute decision
    decision = decision_matrix[j,i]
    element_value = new_df.iloc[j]['Value']
    #element_cost_df.loc[j,i] = decision_cost(decision, element_value)
    #cost = decision_cost(decision, element_value)
    new_df.loc[j, column_names] = decision_cost(decision, element_value)
    # impact condition with decision
    current_condition = new_df.iloc[j]['Condition']
    updated_condition = decision_result(decision, current_condition)
    new_df.loc[j, 'Condition'] = updated_condition
    # degrade element for next period
    degraded_condition = degrade_element(new_df.iloc[j]['Condition'])
    new_df.loc[j, 'Condition'] = degraded_condition
    return(new_df)

    # evaluate decision matrix
    new_df = evaluate_decision_matrix(df, decision_matrix, periods)

    # calculate system condition
    system_condition_values = system_condition(new_df)

    # check if system condition constraints are met
    # returns true if system condition constraints are met
    condition_check = [x > y for x, y in zip(system_condition_values, vals)]
    print(condition_check)

    # check if budget constaint is met
    costs = period_costs(new_df, periods)
    budget_check = [x < y for x, y in zip(costs, max_budget)]
    print(budget_check)


    As an example, the print(condition_check) command displays [True, True, True] indicating the system condition constraints are satisfied. But print(budget_check) shows [True, False, False, False, True, False] indicated 4 of the period budget constraints have been broken.

    Is it possible to structure this as an MIP in python and, if so, how would that be done?

    Continue reading...

Compartilhe esta Página