BookmarkSubscribeRSS Feed
Rakesh
Calcite | Level 5
I have been trying to setup a nonlinear constraint for a genetic algorithm in SAS 9.2 for some time now.
The constraint is as follows;

(-0.3) <= mort(x[1],.,x[2]/12,x[3]) / mort(coeff[1],.,coeff[2]/12,coeff[3]) <= -0.1
Now, the nonlinear optimization calls like "nlpqn" let me specify nonlinear constraints with the "nlc" module. Do we have something similar for genetic algorithms?

Message was edited by: Rakesh Message was edited by: Rakesh
6 REPLIES 6
Rakesh
Calcite | Level 5
My earlier post didn't print properly on the thread. This is what I was trying to say;

I have been trying to setup a nonlinear constraint for a genetic algorithm in SAS 9.2 for some time now.
The constraint is as follows;

(-0.3) LT mort(x[1],.,x[2]/12,x[3]) / mort(coeff[1],.,coeff[2]/12,coeff[3]) LT -0.1

where, LT stands for "Less than or Equal To"

Now, the nonlinear optimization calls like "nlpqn" let me specify nonlinear constraints with the "nlc" module. Do we have something similar for genetic algorithms?
Hutch_sas
SAS Employee
In general, with GA there are several different strategies for satisfying non-linear constraints. Probably the simplest way within IML for this particular problem is to simply "fix up" any solution that does not satisfy the non-linear constraint so that it does match the constraint. In this case, by the nature of the mort() function, the constraint violation function is linear in the first component x[1] ( the initial mortgage amount). That makes it easy to adjust your solution to reside on the nearest constraint boundary by modifying x[1] and leaving the other components unchanged. You can do that in the objective function with something like:

start objective(x) global( coeff );
/* assumes desired soution vector is in x, coeff is constant matrix */

/* First, get the lower (lb) and upper (ub) bounds of the quantity
mort(x[1],.,x[2]/12,x[3])
*/

const = mort(coeff[1],.,coeff[2]/12,coeff[3]); /* denominator */

if const > 0 then do;
ub = -0.1 * const;
lb = -0.3 *const;
end;

else do;
ub = -0.3 * const;
lb = -0.1 * const;
end;

/* Now, fix up x[1] to make sure the constraint is satisfied */

x0 = x[1];
payment = mort(x0,.,x[2]/12,x[3]);

if lb > payment then
x[1] = x0 * lb / payment;

else if payment > ub then
x[1] = x0 * ub / payment;

/* now you have "fixed up" your solution to satisfy the constraint, go ahead and
compute the objective function */

...
Rakesh
Calcite | Level 5
Thanks a lot Hutch. The answer was helpful.

The problem I have is that I need to be able to vary all three parts of the mort() function to achieve this. So, whereas the function is linear in initial balance , it is not in the Interest Rate (x[2]) and the Amortization Term (x[3]). How do I change all three together, how do I distribute the bounds as weighting parameters amongst the three 'variables'?

Do let me know if you have a solution. Your earlier answer did open a few door for me!
Hutch_sas
SAS Employee
Using this strategy you can still vary all three parameters. I assume you can assign reasonable upper and lower bounds for each variable, and then generate a uniform distribution of solutions across those bounds. This fixup strategy then maps in a certian way the solutions that fall outside the constraint to the constraint boundary.

What is your actual objective function for this problem? Depending on your objective, you might also be able to transform variables to produce easier constraints.
Rakesh
Calcite | Level 5
Thanks Hutch.

Below is the code for the objective function i'm trying to maximize;

proc iml;

/* objective function, has minimum of 0 at x = xopt */
start redefault(x) global(coeff);

NewUPB=(1+coeff[14]-x[3]-x[4])*coeff[19];
NewPIPmt=mort((1+coeff[14]-x[3]-x[4])*coeff[19],.,x[1]/12,x[2]-coeff[22]);
OldPIPmt=mort(coeff[19],.,coeff[20]/12,coeff[21]-coeff[22]);
CurrLTV=(1+coeff[14]-x[3]-x[4])*coeff[19]/coeff[18];
LTVBasedOnOrigMV=(1+coeff[14]-x[3]-x[4])*coeff[19]/coeff[17];

/*Upper and Lower Bounds for Chng in Pmt*/
if OldPIPmt > 0 then do;
ub = (1-0.1) * OldPIPmt;
lb = (1-0.3) * OldPIPmt;
end;

else do;
ub = (1-0.3) * OldPIPmt;
lb = (1-0.1) * OldPIPmt;
end;

/*Fixup Variables - NOT BEING USED CURRENTLY*//*
do while (lb>NewPIPmt);
x[1]=x[1]+.000125;
x[2]=x[2]-12;
/*x[3]=x[3]+.005;
x[4]=x[4]+.005;
NewPIPmt=mort((1+coeff[14]-x[3]-x[4])*coeff[19],.,x[1]/12,x[2]-coeff[22]);
end;

do while (NewPIPmt > ub);
x[1]=x[1]-.000125;
NewPIPmt=mort((1+coeff[14]-x[3]-x[4])*coeff[19],.,x[1]/12,x[2]-coeff[22]);
end;
*/


RedefRt=1/(1+exp(-1*
(-5.2815+
1.8953*(NewPIPmt/OldPIPmt-1)+
1.6129*log(1+coeff[2])+
0.1531*coeff[3]+
0.3222*CurrLTV+
0.4368*LTVBasedOnOrigMV+
-2.7613*(coeff[4]- 1) +
0.00531*coeff[5]+
-0.6964*coeff[6]+
-0.2283*coeff[7]+
0.7078*coeff[8]+
0.1932*coeff[9]+
1.2001*coeff[10]+
0.3751*coeff[11]+
0.000808*coeff[12]+
-0.00297*coeff[13]+
0.9974*coeff[14]+
0.1633*coeff[15]+
-0.0949*coeff[16])));

Proceeds = ((mort(.,NewPIPmt,x[1]/12,x[2]-coeff[22]-coeff[2])+(x[3]*coeff[19]))*(1-RedefRt) + coeff[23]*RedefRt);

/* Penalize the children that don't conform to the constraints */
if lb > NewPIPmt | coeff[20] x[2] then
f=.5*Proceeds;
else if NewPIPmt > ub | coeff[20] x[2] then
f=.5*Proceeds;
else f=Proceeds;

return(f);
finish redefault;


Now, the non-linear constraint is that (NewPIPmt/OldPIPmt-1) should be between -0.3 and -0.1, by varying the x[] parts of NewPIPmt.
Hutch_sas
SAS Employee
I don't have complete knowledge of your model, but could you use the ratio:

NewPIPmt/OldPIPmt

as one of your input parameters, instead of what you now have as x[4]? Since your x[4] only appears in the computation of of NewUPB, which would be computed directly from the mort() function, it would then go away and you could use x[4] for the new payment ratio parameter. Mathematically you could then just specify the correct bounds on that ratio directly and eliminate the non-linear constraint. Your objective might look something like this:


/* objective function, has minimum of 0 at x = xopt */
start redefault(x) global(coeff);
OldPIPmt=mort(coeff[19],.,coeff[20]/12,coeff[21]-coeff[22]);
/* let x[4] = NewPIPmt/OldPIPmt */
NewPIPmt = x[4] * OldPIPmt;
/* solve for new principal */
NewUPB = mort( ., NewPIPmt, x[1]/12,x[2]-coeff[22]);
CurrLTV = NewUPB/coeff[18];
LTVBasedOnOrigMV = NewUPB/coeff[17];

RedefRt=1/(1+exp(-1*
(-5.2815+
1.8953*(NewPIPmt/OldPIPmt-1)+
1.6129*log(1+coeff[2])+
0.1531*coeff[3]+
0.3222*CurrLTV+
0.4368*LTVBasedOnOrigMV+
-2.7613*(coeff[4]- 1) +
0.00531*coeff[5]+
-0.6964*coeff[6]+
-0.2283*coeff[7]+
0.7078*coeff[8]+
0.1932*coeff[9]+
1.2001*coeff[10]+
0.3751*coeff[11]+
0.000808*coeff[12]+
-0.00297*coeff[13]+
0.9974*coeff[14]+
0.1633*coeff[15]+
-0.0949*coeff[16])));

Proceeds = ((mort(.,NewPIPmt,x[1]/12,x[2]-coeff[22]-coeff[2])+(x[3]*coeff[19]))*(1-RedefRt) + coeff[23]*RedefRt);

return(Proceeds);
finish;

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

Multiple Linear Regression in SAS

Learn how to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.

Find more tutorials on the SAS Users YouTube channel.

From The DO Loop
Want more? Visit our blog for more articles like these.
Discussion stats
  • 6 replies
  • 1534 views
  • 0 likes
  • 2 in conversation