How to pass a list of lists (N-Dim array) as an argument to the objective function in mystic differential evolution solver?

83 Views Asked by At

I have created an objective function for mystic differential evolution which looks something like this -


import mystic
from mystic.penalty import quadratic_equality,quadratic_inequality,linear_equality
from mystic.solvers import diffev2
from mystic.constraints import as_constraint
from mystic.termination import VTR
from mystic.strategy import Best1Exp
from mystic.monitors import VerboseMonitor
from mystic.symbolic import generate_constraint, generate_penalty
from mystic.tools import getch, random_seed
# Differential Evolution solver
# from mystic.solvers import DifferentialEvolutionSolver2
import pandas as pd
import json
import numpy as np
from mystic.math import poly1d
from mystic.solvers import DifferentialEvolutionSolver2
import random
from itertools import repeat



gsv=0
volume=0
rsv=0
nsv=0
tpe=0
mac=0
mac_perc=0
customer_margin=0
customer_margin_perc=0
output_penalty=0



def objective(x):
    
    global gsv
    global volume
    global rsv
    global nsv
    global tpe
    global mac
    global mac_perc
    global customer_margin
    global customer_margin_perc
    
    non_edlp_weeks_change,non_edlp_bp_perc_change,non_edlp_wod_change,non_edlp_pp_perc_change,edlp_weeks_change,edlp_price_perc_change = x

    df['CUSTOMER_MARGIN_PERC']=df['CUSTOMER_MARGIN']/df['RSV']*(1+df['VAT_PERC'])
    df['MAC_PERC']=df['MAC']/df['NSV']
    
    #new base price
    df.loc[df['EDLP_FLAG']==0,'NEW_BASE_PRICE_PER_UNIT']=df['BASE_PRICE_PER_UNIT']*(1+non_edlp_bp_perc_change)
    df.loc[df['EDLP_FLAG']==1,'NEW_BASE_PRICE_PER_UNIT']=df['BASE_PRICE_PER_UNIT']
    
    #new promo price
    df.loc[df['EDLP_FLAG']==0,'NEW_PROMO_PRICE_PER_UNIT']=df["PROMO_PRICE_PER_UNIT"]*(1+non_edlp_pp_perc_change)
    df.loc[df['EDLP_FLAG']==1,'NEW_PROMO_PRICE_PER_UNIT']=df["PROMO_PRICE_PER_UNIT"]*(1+edlp_pp_perc_change)
    
    #new list price
    df.loc[df['EDLP_FLAG']==0,'NEW_LIST_PRICE']=df['LIST_PRICE']*(1+non_edlp_bp_perc_change)
    df.loc[df['EDLP_FLAG']==1,'NEW_LIST_PRICE']=df['LIST_PRICE']
    
    #new ltd edlp per unit
    df.loc[df['EDLP_FLAG']==0,'NEW_LTD_EDLP_PER_UNIT']=df['LTD_EDLP_PER_UNIT']*(1+non_edlp_bp_perc_change)
    df.loc[df['EDLP_FLAG']==1,'NEW_LTD_EDLP_PER_UNIT']=df['LTD_EDLP_PER_UNIT']
    
    #NEW_PROMO_FUNDING_PER_UNIT
    
    df['NEW_PROMO_FUNDING_PER_UNIT']=df['NEW_BASE_PRICE_PER_UNIT']/(1+df['VAT_PERC'])*(1-df['CUSTOMER_MARGIN'])-df['NEW_PROMO_PRICE_PER_UNIT']/(1+df['VAT_PERC'])*(1-df['CUSTOMER_MARGIN_PROMO'])
    
    #NEW_NON_PROMO_VOLUME_PER_WEEK
    
    df.loc[df['EDLP_FLAG']==0,'NEW_NON_PROMO_VOLUME_PER_WEEK']=df['NON_PROMO_VOLUME_PER_WEEK']*(1+non_edlp_bp_perc_change*df['BP_ELAS'])
    df.loc[df['EDLP_FLAG']==1,'NEW_NON_PROMO_VOLUME_PER_WEEK']=0
    
    #NEW_PROMO_VOLUME_PER_WEEK
    df.loc[df['EDLP_FLAG']==0,'NEW_PROMO_VOLUME_PER_WEEK']=df['PROMO_VOLUME_PER_WEEK']*(1+non_edlp_pp_perc_change*df['PROMO_PRICE_ELAS'])
    df.loc[df['EDLP_FLAG']==0,'NEW_PROMO_VOLUME_PER_WEEK']=df['PROMO_VOLUME_PER_WEEK']*(1+edlp_pp_perc_change*df['PROMO_PRICE_ELAS'])
    
    #new non promo volume
    df.loc[(df['TOTAL_WEEKS']>0 & (df['WOD']==df['TOTAL_WEEKS'])),'NEW_NON_PROMO_VOLUME']=df['TOTAL_WEEKS']*df['NEW_NON_PROMO_VOLUME_PER_WEEK']
    df.loc[(df['TOTAL_WEEKS']<=0 | (df['WOD']==df['TOTAL_WEEKS'])),'NEW_NON_PROMO_VOLUME']=(df['TOTAL_WEEKS']-df['WOD'])*df['NEW_NON_PROMO_VOLUME_PER_WEEK']
    
    
    #new promo volume
    df.loc[df['EDLP_FLAG']==0,'NEW_PROMO_VOLUME']= df['NEW_PROMO_VOLUME_PER_WEEK']*(df['WOD']+non_edlp_wod_change)+(df['FEATURE_TDP']*df['FEATURE_LIFT'])
    df.loc[df['EDLP_FLAG']==1,'NEW_PROMO_VOLUME']= df['NEW_PROMO_VOLUME_PER_WEEK']*(df['WOD'])+(df['FEATURE_TDP']*df['FEATURE_LIFT'])
    
    
    #new volume units
    df['NEW_VOLUME_UNITS']=df['NEW_PROMO_VOLUME']+df['NEW_NON_PROMO_VOLUME']
    
    #NEW RSV
    df['NEW_RSV']=df['NEW_NON_PROMO_VOLUME']*df['NEW_BASE_PRICE_PER_UNIT']+df['NEW_PROMO_VOLUME']*df['NEW_PROMO_PRICE_PER_UNIT']
    
    #new GSV
    df['NEW_GSV']=df['NEW_LIST_PRICE']*df['NEW_VOLUME_UNITS']
    
    #new trade spends
    df['NEW_TRADE_SPENDS']=df['NEW_PROMO_FUNDING_PER_UNIT']*df['NEW_PROMO_VOLUME']
    

    #new tpe
    df['NEW_TPE']=df['NEW_TRADE_SPENDS']+df['NEW_LTD_EDLP_PER_UNIT']+df['GINC_PER_UNIT']*df['NEW_VOLUME_UNITS']+df['ADJUSTED_TRADE_SPENDS']
    
    #new NSV
    df['NEW_NSV']=df['NEW_GSV']-df['NEW_TPE']
    
    #new mac
    df['NEW_MAC']=df['NEW_NSV']-df['NEW_VOLUME_UNITS']*df['COGS_PER_UNIT']
    
    #new MAC perc
    df['NEW_MAC_PERC']=df['NEW_MAC']/df['NEW_NSV']
    
    #new cust marging incl ginc
    df['NEW_CUSTOMER_MARGIN_INCL_GINC']=df['NEW_RSV']/(1+df['VAT_PERC']-df['NEW_NSV'])
    
    #new customer margin perc
    df['NEW_CUSTOMER_MARGIN_PERC']=df['NEW_CUSTOMER_MARGIN_INCL_GINC']/df['NEW_RSV']*(1+df['VAT_PERC'])
    
    #replace all nan by 0
    df.replace(np.nan,0,inplace=True)

    volume=df['NEW_VOLUME_UNITS'].sum()
    rsv=df['NEW_RSV'].sum()
    gsv=df['NEW_GSV'].sum()
    trade_spends=df['NEW_TRADE_SPENDS'].sum()
    tpe=df['NEW_TPE'].sum()
    nsv=df['NEW_NSV'].sum()
    mac=df['NEW_MAC'].sum()
    mac_perc=mac/nsv
    customer_margin=df['NEW_CUSTOMER_MARGIN_INCL_GINC'].sum()
    customer_margin_perc=customer_margin/rsv*(1+df['VAT_PERC'].max())



    if (constraints.get('optimization_target')=='maximize_volume'):
        return -((volume))
    elif(constraints.get('optimization_target')=='maximize_rsv'):
        return -((rsv))
    elif(constraints.get('optimization_target')=='maximize_gsv'):
        return -((gsv))
    elif(constraints.get('optimization_target')=='maximize_nsv'):
        return(-(nsv))
    elif(constraints.get('optimization_target')=='maximize_mac_margin'):
        return(-(mac))
    elif(constraints.get('optimization_target')=='maximize_mac_perc'):
        return(-(mac_perc))
    elif(constraints.get('optimization_target')=='maximize_customer_margin'):
        return(-(customer_margin))
    elif(constraints.get('optimization_target')=='maximize_customer_margin_perc'):
        return(-(customer_margin_perc))
    elif(constraints.get('optimization_target')=='minimize_tpe'):
        return((tpe))
      

constraints is an input json object determining the bound values for x - where non_edlp_weeks_change,non_edlp_bp_perc_change,non_edlp_wod_change,non_edlp_pp_perc_change,edlp_weeks_change,edlp_price_perc_change = x

constraints = [[0, 52], [0.06, 0.12], [6, 11], [0.02, 0.05], [-52, 0], [0.02, 0.1]]

what i want to do is have a different value of x (ie. these constraints) for each unique row in my df. The objective function should then optimize across the complete df for all of these various values of x (unique to each row)

I Have figured out how to pass one value for x(1-D array) in the objective function. What I am struggling is with trying to pass N-Dim array (of x values satisfying the constraints, len = nrow (df)) to the objective function and then optimize for the various functions.

Output required is this N-Dim array of x values satisfying my constraints and optimizing for my objective target

0

There are 0 best solutions below