I am currently trying to create a model where the results of the objective function when applied to all rows in the problem will be used for recommendation purposes.
!********************************************************************************
! 1. Import Modules
! 2. This part is used to define result format and directories
!********************************************************************************
model "savings portfolio"
uses "mmxprs", "mmsheet"
parameters
CAPITAL = 100000000
INPUTFILE = "C:/Users/Admin/Downloads/201031_SAVINGS_ACCOUNTS3_v1.0.xlsx"! 3. File directory for data file
RESULTFILE = "C:/Users/Admin/Downloads/201031_SAVINGRESULTS3_v1.0.xlsx"! 4. File directory for result file
end-parameters
!********************************************************************************
! 5. Declare variable types
! 6. Variable types as well as the mpvar must be declared first before importing data
!********************************************************************************
declarations
INDEX: set of integer
PRODUCTNAME: array(INDEX) of string
MONTH: array(INDEX) of integer
MONTH2: array(INDEX) of integer
MININVEST: array(INDEX) of integer
MININVEST2: array(INDEX) of integer
PRINCIPAL: array(INDEX) of mpvar ! 7. mpvar refers to the variable that is to be optimized
PRINCIPAL2: array(INDEX) of mpvar
INTEREST: array(INDEX) of real
INTEREST2: array(INDEX) of real
end-declarations
!********************************************************************************
! 8. "XPRS_VERBOSE" settings: Enable to view problem statistics
!********************************************************************************
setparam("XPRS_VERBOSE", true)
!********************************************************************************
! 9. Read data
!********************************************************************************
initializations from "mmsheet.xlsx:"+INPUTFILE
[PRODUCTNAME,INTEREST,MONTH,MININVEST,INTEREST2,MONTH2,MININVEST2] as "[Sheet1$A2:H501]" !10.Select data from excel sheet excluding headers, must include index column
end-initializations
!********************************************************************************
! 11. Calculating YEAR
!********************************************************************************
forall(i in INDEX) YEAR(i):=MONTH(i)/12
forall(i in INDEX) YEAR2(i):=MONTH2(i)/12
!********************************************************************************
! 12. Objective Function
!********************************************************************************
SUMDIFF:=sum(i in INDEX) (PRINCIPAL(i)*(1+(INTEREST(i)/MONTH(i)))^(MONTH(i)*getsol(YEAR(i))) - PRINCIPAL2(i)*(1+(INTEREST2(i)/MONTH2(i)))^(MONTH2(i)*getsol(YEAR(i))))
!********************************************************************************
! 13. Constraints
!********************************************************************************
sum(i in INDEX) PRINCIPAL(i) = CAPITAL
sum(i in INDEX) PRINCIPAL2(i) = CAPITAL
forall(i in INDEX) PRINCIPAL(i) >= MININVEST(i)
forall(i in INDEX) PRINCIPAL2(i) >= MININVEST2(i)
SUMDIFF >= 0
!********************************************************************************
! 14. Optimization method
!********************************************************************************
maximize(SUMDIFF)
!********************************************************************************
! 15. Calculate variables
!********************************************************************************
forall(i in INDEX) PRINSTANDIFF(i):=(getsol(PRINCIPAL(i))*(1+(INTEREST(i)/MONTH(i)))^(MONTH(i)*getsol(YEAR(i)))) - (getsol(PRINCIPAL2(i))*(1+(INTEREST2(i)/MONTH2(i)))^(MONTH2(i)*getsol(YEAR(i))))
forall(i in INDEX) INVESTMENT1(i):=getsol(PRINCIPAL(i))
forall(i in INDEX) INVESTMENT2(i):=getsol(PRINCIPAL2(i))
initializations to "mmsheet.xlsx:"+RESULTFILE
[PRODUCTNAME,INVESTMENT1,INVESTMENT2,PRINSTANDIFF] as "grow;[Sheet1$A2:E2]"
end-initializations
end-model
The purpose of this model is to use the values in PRINSTANDIFF to decide which option to invest in. If the resulting value is positive, Option 1 (INVESTMENT1) is the better option whereas if the value is negative, Option 2 (INVESTMENT2) is the better option.
My question is, is there a way to control the number of positive values and negative values I can get from the model via constraints? I would ideally like to keep the number of positives and negatives at a minimum ratio of 6:4 and a maximum ratio of 7:3.
Elaborating on my comment and turning it into an answer: Tasks like the one you describe can be achieved by indicator constraints.
The idea is to introduce binary helper variables that are 1 if an expression is positive and 0 if it is negative:
and then connect those with the sign of an expression via indicator constraints
With this,
SIGN(i)is 1 ifEXPR(i)is non-negative andSIGN(i)is 0 ifEXPR(i)is non-positive.Now you can write the number of positive expressions as
sum(i in INDEX) SIGN(i)and the number of negative expressions assum(i in INDEX) (1 - SIGN(i)). Thus a ratio on the two can be enforced viaThe only problem left is to define
EXPR(i)appropriately as an expression in mpvars. This may be an issue here since it seems to involve some non-linearities.