#include "tool.h"
/*
########################################################################
#
# KEYS: DDP model optimization tool
# Clustering Variant
# Copyright (C) 2007-2009 Omid Jalali, Gregory Gay
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
########################################################################
*/
int costFlag, attFlag, displayFlag, randomFlag, runFlag, maxFutileFlag;
float costLimit, attLimit;
int Seed;
int RunTotal;
float FixedMitigations[TotalMitigations+1];
float mArray[TotalMitigations+1];
float decayMid[101];
float decayTop[101];
int mCounter,era,run,TotalInstances,instanceCounter,displayMode, TotalTopInstances,TotalMidInstances, FixedInstances;
float MinCost,MaxCost,MinAtt,MaxAtt, PosCost,PosAtt;
float infinity,small;
int recentSetMitigation;
float recentSetMitigationStatus;
float LastMinCost,LastMaxAtt;
int main(int argc, char **argv)
{
//this is required to set up the ddp model.
setupModel();
Seed = 0;
char *costValue = NULL;
char *attValue = NULL;
char *displayValue = NULL;
char *randomValue = NULL;
char *runValue = NULL;
char *futileValue = NULL;
int c;
int futile = 0;
int MaxFutile;
displayFlag = 0;
costFlag = 0;
attFlag = 0;
randomFlag = 0;
runFlag = 0;
maxFutileFlag = 0;
infinity = pow(10,20);
small = pow(10,-20);
opterr = 0;
while ((c = getopt(argc, argv, "a:c:d:f:h:r:t:")) != -1)
{
switch (c)
{
case 'a':
attFlag = 1;
attValue = optarg;
break;
case 'c':
costFlag = 1;
costValue = optarg;
break;
case 'd':
displayFlag = 1;
displayValue = optarg;
break;
case 'f':
maxFutileFlag = 1;
futileValue = optarg;
break;
case 'r':
randomFlag = 1;
randomValue = optarg;
break;
case 't':
runFlag = 1;
runValue = optarg;
break;
case 'h':
case '?':
printf("\nThe options must have the format -a AttainmentLowerLimit -c CostUpperLimit -d DisplayMode -f Futile -r Seed -t TotalRuns.\n");
printf("\nAttainmentLowerLimit:\n\tThis is the lower limit that the user can set for attainment.\n");
printf("\tThe tool tries to find a mitigation set that gives an attainment equal to or higher than this value.\n");
printf("\tHowever, this is not guaranteed especially for limits set too high.\n");
printf("\nCostUpperLimit:\n\tThis is the upper limit that the user can set for cost.\n");
printf("\tThe tool tries to find a mitigation set that gives a cost equal to or lower than this value.\n");
printf("\tHowever, this is not guaranteed especially for limits set too low.\n");
printf("\nDisplay Mode:\n\tDisplay mode 1 prints the final results.\n");
printf("\tDisplay mode 2 prints median and spread of each mitigation-fixing round.\n");
printf("\tDisplay mode 3 is for debugging purposes only and prints everything needed.\n");
printf("\tDisplay mode 4 is for debugging purposes only and prints cost and attainment of each run.\n");
printf("\nFutile:\n\tThis is the number of trials before the tool decides that no improvements were seen.\n");
printf("\tIt can be a number between 1 and the number of mitigations used.\n");
printf("\tIt can be turned off by setting it the number of mitigations used. The default value is 10.\n");
printf("\nSeed:\n\tSeed is used in random number generation. By default, it is generated using the system time.\n");
printf("\nTotalRuns:\n\tThe number of total runs that is used internally. The default value is 100.\n");
printf("\n");
return(1);
break;
default:
break;
}
}
if (attFlag == 1 && attValue != NULL)
attLimit = (float)atof(attValue);
else
attLimit = -infinity;
if (costFlag == 1 && costValue != NULL)
costLimit = (float)atof(costValue);
else
costLimit = infinity;
if (randomFlag == 1 && randomValue != NULL)
Seed = atoi(randomValue);
else
Seed = 1;
if (runFlag == 1 && runValue != NULL)
RunTotal = atoi(runValue);
else
RunTotal = 100;
if (displayFlag == 1 && displayValue != NULL)
displayMode = atoi(displayValue);
else
displayMode = 1;
if (maxFutileFlag == 1 && futileValue != NULL)
MaxFutile = atoi(futileValue);
else
MaxFutile = 1000000;
float att, cost;
float *Distance = new float[RunTotal+1];
float **Data = new float*[RunTotal+1];
float **TopInstances = new float*[RunTotal+1];
float **MidInstances = new float*[RunTotal+1];
for (int i = 0; i < RunTotal + 1; i++)
{
Data[i] = new float[TotalMitigations+2];
TopInstances[i] = new float[TotalMitigations+2];
MidInstances[i] = new float[TotalMitigations+2];
}
if (randomFlag == 1)
srand(Seed);
else
srand((unsigned int)time(NULL));
//set all mitigations to non-fixed value of -1
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
FixedMitigations[mCounter] = -1;
if (displayMode == 2)
printf("Era, Mitigation Number, Mitigation Value, Median of Cost, Spread of Cost, Median of Attainment, Spread of Attainment\n");
MinCost = infinity;
MaxCost = -infinity;
MinAtt = infinity;
MaxAtt = -infinity;
LastMinCost = MinCost;
LastMaxAtt = MaxAtt;
//Find the max cost, max att
int x;
for(x=1;x<=TotalMitigations;x++){
mArray[x]=1;
}
model(&cost,&att,mArray);
PosCost = cost;
PosAtt = att;
//printf("%.1f,%.5f\n",cost,att);
for(x=1;x<=TotalMitigations;x++){
mArray[x]=0;
}
int midtotal=0;
int toptotal=0;
int mids,tops, randomNum;
for (era = 1; era <= TotalMitigations; era++)
{
TotalInstances = 0;
//Decrement decay counter
int dCounter;
for(dCounter=1;dCounter(PosCost*0.1))&&(att>(PosAtt*0.65)))
addMidInstance(cost,att,MidInstances);
else if((cost<=(PosCost*0.1))&&(att>(PosAtt*0.9)))
addTopInstance(cost,att,TopInstances);
}
//find the sweet spot and distances from sweet spot for each distance
sweetSpot(Data, Distance);
//rank the mitigations and find the mitigation that should be fixed
rankMitigations(Data, Distance);
if (displayMode == 2)
reportMedianAndSpread(Data);
// printf("%d,futile:%d,%f,last:%f,%f,last:%f\n",era,futile,MinCost,LastMinCost,MaxAtt,LastMaxAtt);
if (MinCost < LastMinCost && MaxAtt >= LastMaxAtt)
{
LastMinCost = MinCost;
LastMaxAtt = MaxAtt;
futile = 0;
}
else if (futile > MaxFutile)
{
if (displayMode == 1 || displayMode == 3)
printf("Terminated at era: %d\n",era);
era = TotalMitigations + 1;
futile++;
}
else
futile++;
}
//show the final results
if (displayMode == 1 || displayMode == 3)
{
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
{
mArray[mCounter] = FixedMitigations[mCounter];
if (FixedMitigations[mCounter] == -1)
mArray[mCounter] = 0;
}
model(&cost,&att,mArray);
for (mCounter=1; mCounter<=TotalMitigations; mCounter++)
printf("m[%d],",mCounter);
printf("cost,attainment\n");
for (mCounter=1; mCounter<=TotalMitigations; mCounter++)
printf("%.0f,", mArray[mCounter]);
printf("%.1f,%.5f\n",cost,att);
}
}
void reportMedianAndSpread(float** Data)
{
float tempCostArray[TotalInstances], tempAttArray[TotalInstances];
float costMedian,costSpread,attMedian,attSpread;
//sort the cost and att (individually) and find the median and spread
for (instanceCounter = 1; instanceCounter <= TotalInstances; instanceCounter++)
{
tempCostArray[instanceCounter] = Data[instanceCounter][1];
tempAttArray[instanceCounter] = Data[instanceCounter][2];
}
findMedianAndSpread(tempCostArray,TotalInstances,&costMedian,&costSpread);
findMedianAndSpread(tempAttArray,TotalInstances,&attMedian,&attSpread);
printf("%d,%d,%.0f,%.5f,%.5f,%.5f,%.5f\n",era,recentSetMitigation,recentSetMitigationStatus,costMedian,costSpread,attMedian,attSpread);
}
void findMedianAndSpread(float inputArray[], int size, float *median, float *spread)
{
float tempValue;
int i,j;
float tempArray[size];
for (i = 1; i <= size; i++)
tempArray[i] = inputArray[i];
//sort
for (i = 1; i <= size; i++)
{
tempValue = tempArray[i];
j = i;
while ((j > 1) && (tempArray[j-1] > tempValue))
{
tempArray[j] = tempArray[j-1];
j = j - 1;
}
tempArray[j] = tempValue;
}
*median = tempArray[size/2];
*spread = tempArray[3*size/4] - tempArray[size/2];
}
float findBestDistance(float inputArray[], int size)
{
float tempValue;
int i,j;
float tempArray[size];
for (i = 1; i <= size; i++)
tempArray[i] = inputArray[i];
//sort
for (i = 1; i <= size; i++)
{
tempValue = tempArray[i];
j = i;
while ((j > 1) && (tempArray[j-1] > tempValue))
{
tempArray[j] = tempArray[j-1];
j = j - 1;
}
tempArray[j] = tempValue;
}
return tempArray[int(0.1*size)];
}
void rankMitigations(float** Data, float* Distance)
{
float tempScoreOff[TotalMitigations],tempScoreOn[TotalMitigations],tempBestFreqCount[TotalMitigations][2],tempRestFreqCount[TotalMitigations][2];
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
{
tempBestFreqCount[mCounter][0] = 0;
tempBestFreqCount[mCounter][1] = 0;
tempRestFreqCount[mCounter][0] = 0;
tempRestFreqCount[mCounter][1] = 0;
}
float bestValue = findBestDistance(Distance,TotalInstances);
for (instanceCounter = 1; instanceCounter <= TotalInstances; instanceCounter++)
{
if (displayMode == 3)
{
for (mCounter=1; mCounter<=TotalMitigations; mCounter++)
printf("%.0f,",Data[instanceCounter][mCounter+2]);
printf("%.3f,%.3f,\t", Data[instanceCounter][1],Data[instanceCounter][2]);
}
//if it is in the Best distance from the sweet spot, count the frequency of each mitigation (0 and 1) for the best instances
if (Distance[instanceCounter] <= bestValue)
{
if (displayMode == 3) printf("%.3f best from %.3f\n", Distance[instanceCounter],bestValue);
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
{
//keep track of the mitigation's counts if it is not already fixed
if (FixedMitigations[mCounter] == -1)
{
if (Data[instanceCounter][mCounter+2] == 0)
tempBestFreqCount[mCounter][0]++;
else if (Data[instanceCounter][mCounter+2] == 1)
tempBestFreqCount[mCounter][1]++;
}
}
}
//else it is in the Rest distance from the sweet spot and so count the frequency of each mitigation (0 and 1) for the rest instances
else
{
if (displayMode == 3) printf("%.3f rest from %.3f\n", Distance[instanceCounter],bestValue);
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
{
//keep track of the mitigation's counts if it is not already fixed
if (FixedMitigations[mCounter] == -1)
{
if (Data[instanceCounter][mCounter+2] == 0)
tempRestFreqCount[mCounter][0]++;
else if (Data[instanceCounter][mCounter+2] == 1)
tempRestFreqCount[mCounter][1]++;
}
}
}
}
float maxScore = -infinity;
int maxScoredMitigation = 0;
float maxScoredMitigationStatus = -1;
float best,rest;
//normalize each frequency count by dividing it by the total number of instances and score each mitigation using the best^2/(best+rest) and keep min and max
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
{
//do this only if mitigation is not fixed already
if (FixedMitigations[mCounter] == -1)
{
//find the score of the mitigation when it is off
best = tempBestFreqCount[mCounter][0]/TotalInstances;
rest = tempRestFreqCount[mCounter][0]/TotalInstances;
if (best == 0 && rest == 0)
tempScoreOff[mCounter] = 0;
else
tempScoreOff[mCounter] = pow(best,2)/(best+rest);
if (displayMode == 3) printf( "m%d with best:%.3f and rest:%.3f\n",mCounter,best,rest);
//keep its information if it is the max score seen so far
if (tempScoreOff[mCounter] > maxScore)
{
maxScore = tempScoreOff[mCounter];
maxScoredMitigation = mCounter;
maxScoredMitigationStatus = 0;
}
//find the score of the mitigation when it is on
best = tempBestFreqCount[mCounter][1]/TotalInstances;
rest = tempRestFreqCount[mCounter][1]/TotalInstances;
if (best == 0 && rest == 0)
tempScoreOn[mCounter] = 0;
else
tempScoreOn[mCounter] = pow(best,2)/(best+rest);
if (displayMode == 3) printf( "m%d with best:%.3f and rest:%.3f\n",mCounter,best,rest);
//keep its information if it is the max score seen so far
if (tempScoreOn[mCounter] > maxScore)
{
maxScore = tempScoreOn[mCounter];
maxScoredMitigation = mCounter;
maxScoredMitigationStatus = 1;
}
if (displayMode == 3) printf( "score of m%d 0:%.3f 1:%.3f\n",mCounter,tempScoreOff[mCounter],tempScoreOn[mCounter]);
}
}
if (displayMode == 3) printf( "chosen mitigation is m%d with status %.0f has score %.3f\n",maxScoredMitigation,maxScoredMitigationStatus,maxScore);
FixedMitigations[maxScoredMitigation] = maxScoredMitigationStatus;
recentSetMitigation = maxScoredMitigation;
recentSetMitigationStatus = maxScoredMitigationStatus;
}
void sweetSpot(float** Data, float* Distance)
{
if (costFlag == 1)
MaxCost = costLimit;
if (attFlag == 1)
MinAtt = attLimit;
if (displayMode == 3) printf("MIN and MAX %.3f,%.3f,%.3f,%.3f\n",MinCost,MaxCost,MinAtt,MaxAtt);
float normalizedCost,normalizedAtt;
//normalize the att and cost using their
for (instanceCounter = 1; instanceCounter <= TotalInstances; instanceCounter++)
{
normalizedCost = (Data[instanceCounter][1] - MinCost)/(MaxCost - MinCost + small);
normalizedAtt = (Data[instanceCounter][2] - MinAtt)/(MaxAtt - MinAtt + small);
Distance[instanceCounter] = pow(pow((normalizedCost - 0),2) + pow((normalizedAtt - 1),2),0.5);
}
}
int selectValue(int val1, int val2)
{
double randomValue = (double)rand()/((double)(RAND_MAX)+(double)(1));
int returnValue;
if (randomValue < 0.5)
returnValue = val1;
else
returnValue = val2;
return returnValue;
}
void addInstance(float costVar, float attVar, float** Data)
{
TotalInstances++;
Data[TotalInstances][1] = costVar;
Data[TotalInstances][2] = attVar;
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
Data[TotalInstances][mCounter+2] = mArray[mCounter];
if (MinCost > Data[TotalInstances][1])
MinCost = Data[TotalInstances][1];
if (MaxCost < Data[TotalInstances][1])
MaxCost = Data[TotalInstances][1];
if (MinAtt > Data[TotalInstances][2])
MinAtt = Data[TotalInstances][2];
if (MaxAtt < Data[TotalInstances][2])
MaxAtt = Data[TotalInstances][2];
}
void addTopInstance(float costVar, float attVar, float** Data)
{
if(TotalTopInstances>=RunTotal)
{
int dCounter;
for(dCounter=1;dCounter<=TotalTopInstances;dCounter++)
{
if(decayTop[dCounter]<=0)
{
Data[dCounter][1] = costVar;
Data[dCounter][2] = attVar;
decayTop[dCounter]=5;
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
Data[dCounter][mCounter+2] = mArray[mCounter];
break;
}
}
}
else{
TotalTopInstances++;
Data[TotalTopInstances][1] = costVar;
Data[TotalTopInstances][2] = attVar;
decayTop[TotalTopInstances]=5;
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
Data[TotalTopInstances][mCounter+2] = mArray[mCounter];
}
}
void addMidInstance(float costVar, float attVar, float** Data)
{
if(TotalMidInstances>=RunTotal)
{
int dCounter;
for(dCounter=1;dCounter<=TotalMidInstances;dCounter++)
{
if(decayMid[dCounter]<=0)
{
Data[dCounter][1] = costVar;
Data[dCounter][2] = attVar;
decayMid[dCounter]=5;
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
Data[dCounter][mCounter+2] = mArray[mCounter];
break;
}
}
}
else{
TotalMidInstances++;
Data[TotalMidInstances][1] = costVar;
Data[TotalMidInstances][2] = attVar;
decayMid[TotalMidInstances]=5;
for (mCounter = 1; mCounter <= TotalMitigations; mCounter++)
Data[TotalMidInstances][mCounter+2] = mArray[mCounter];
}
}
float minValue(float val1, float val2)
{
if (val1 < val2)
return val1;
else
return val2;
}