This code is also available on https://gist.github.com/c8e3699a46c629b5cbdb
package SA;
/** current output SA: Starting Application === Binary options (0, 1) Total amount of criteria: 16
Total amount of combinations: 65536 Favor Native: 38360
Favor Hybrid: 6960 Favor Web: 11396 No Favor: 8820
Now with minimum of 5 criteria (total of: 16)
Total amount of combinations: 63019 (total of: 65536) Favor Native: 37150 (total of: 38360)
Favor Hybrid: 6731 (total of: 6960) Favor Web: 10729 (total of: 11396) No Favor: 8409 (total of: 8820)
=== Ternary option (-1, 0, 1) Total amount of criteria: 16
Total amount of combinations: 43046721 Favor Native: 16635006
Favor Hybrid: 4361872 Favor Web: 18145746 No Favor: 3904097
Now with minimum of 5 criteria (total of: 16)
Total amount of combinations: 43012608 (total of: 43046721) Favor Native: 16622515 (total of: 16635006)
Favor Hybrid: 4358913 (total of: 4361872) Favor Web: 18131918 (total of: 18145746) No Favor: 3899262 (total of: 3904097) SA: Ending Application
*/
/**
* class SA :: Sensitivity Analysis
* This class takes a weighted decision matrix, and calculates all possible scenarios; by enabling or disabling criteria
* The summary shows which platform is favored, based on the weights of the criteria
* @Author: Ernst Fluttert * @Date: 29 august 2012 */
public class SA {
// outcome variables private int outcomeWeb; private int outcomeWebMC; private int outcomeNative; private int outcomeNativeMC; private int outcomeHybrid; private int outcomeHybridMC;
private int outcomeUndecided; private int outcomeUndecidedMC; private int outcomeTotal; private int outcomeTotalMC;
private int minimumCriteria = 5; // only count with minimum amount of
involved criteria
// list of criteria, each with 4 weights (impact, native, hybrid, web)
private int[][] criteria; // the list of criteria
private String[] criteriaNames; // name of the criteria
// constructor, initializes the numbers and criteria public SA(){
// put counters on 0 resetCounter();
criteria = new int[16][4];
// === criteria (weight, native, hybrid, web) // C1 connectivity (offline access?)
criteria[0] = new int[]{2, 2, 1, -1}; // C2 Device Sensor usage
criteria[1] = new int[]{2, 2, 1, -1}; // C3 Market (app must be in market) criteria[2] = new int[]{2, 2, 2, 0}; // C4 Amount of platforms (more than 1?) criteria[3] = new int[]{3, 0, 1, 2};
// C5 Mechanisms (do you need native functions) criteria[4] = new int[]{2, 2, 1, -1};
// C6 Content (text and image only?) criteria[5] = new int[]{2, 0, 1, 2};
// C7 Updatability (multiple versions planned?) criteria[6] = new int[]{1, 0, 1, 2};
// C8 personalisation (personalized content) criteria[7] = new int[]{1, 2, 1, 0};
// C9 responsiveness (immediate vs delayed) criteria[8] = new int[]{1, 2, 1, 0};
// C10 native ui elements like hardware buttons and look and feel criteria[9] = new int[]{1, 2, 0, 0};
// C11 Screensize, also support pads? criteria[10] = new int[]{1, 0, 1, 2};
// C12 heterogeneity device number of hardware devices criteria[11] = new int[]{1, 0, 2, 2};
// C13 user expectation, high expectation? criteria[12] = new int[]{1, 2, 1, 0};
// C14 Encrypted data?
criteria[13] = new int[]{1, 2, 1, 2}; // C15 Market fee: use transactions? criteria[14] = new int[]{1, 0, 0, 2}; // C16 market regulations
criteria[15] = new int[]{1, 0, 0, 2}; }
// reset the counters to zero public void resetCounter(){
outcomeWeb = 0; outcomeWebMC = 0; outcomeNative = 0; outcomeNativeMC = 0; outcomeHybrid = 0; outcomeHybridMC = 0; outcomeUndecided = 0; outcomeUndecidedMC = 0; outcomeTotal = 0; outcomeTotalMC = 0; }
// function run: starts the test. Calculates all possible mutations, and passes this off for analysis
public void run(){
// determine number of criteria
int numberOfCriteria = criteria.length; // First Run: binary choices ( 0 , 1) binaryChoice(numberOfCriteria);
System.out.println("=== Binary options (0, 1) "); stats();
// reset stats before second run resetCounter();
// Second Run: Ternary choice ( -1 , 0, and 1) ternaryChoice(0, numberOfCriteria, "");
System.out.println(" ");
System.out.println("=== Ternary option (-1 , 0, 1) "); stats();
}
// all possibilities for a binary option (yes or no) public void binaryChoice(int numberOfCriteria){
// to calculate every combination of criteria (either on or off)
// This is done by taking taking 2 to the power of number of criteria ( 3 criteria would yield 8 possibilities, 5 criteria would yield 32 etc)
for (int i = 0; i < Math.pow(2, numberOfCriteria); i++) {
// the magic step is to create the binary representation of the number
String binaryRep = Integer.toBinaryString(i); while (binaryRep.length() < numberOfCriteria){ // is it the specified length?, output should be
binaryRep = "0" + binaryRep; // add leading zero's
}
calcRow(binaryRep, true); // process
the criteria as binary }
}
// all possibilities for a ternary option ( inverse norm - doesnt apply - norm)
public void ternaryChoice(int depth, int maxdepth, String row){ if(depth == maxdepth){
// maximum depth reached please calculate the values per platforms calcRow(row, false); // process criteria as ternary
return; // done with recursion :P
} else{
String origRow = row; for(int i = 0; i<3; i++){
//System.out.println("i="+i+" depth:"+ (depth+1) + " maxdepth:"+maxdepth);
// continue with recursion
ternaryChoice(depth+1, maxdepth, origRow+i); }
} }
// function calcRow: Takes a binary string (like "0011101010"), and calculates the weight per platform, based on the weight specified in the constructor
public void calcRow(String cr, boolean binary){ // convert the string to a character array char[] crt = cr.toCharArray();
int correction = 0;
if(!binary){correction = 1;}
// cr = current row. This is a string with 0 or 1 for each criteria // cr[0,1,0] = only the second criteria is enabled. Please calculate the result of this for each platform
int on = 0; // native platform
int oh = 0; // hybrid platform
int ow = 0; // web platform
int crl = crt.length; // length of row
int ec = 0; // number of enabled criteria
// determine if minimum amount of criteria is applied for(int z=0; z<crl; z++){
int curval = (Integer.parseInt( Character.toString(crt[z]) ) - correction);
if(curval== -1 || curval == 1 ){ec++;} }
// process the string again for values for(int z=0; z<crl; z++){
//System.out.println("crl: "+ crl +" z:" + z + " on:" + on + " crt(z):" + (crt[z]) + " (int)crt[z]: " + Integer.parseInt(
Character.toString(crt[z]) ) );
// SUM the enabled criteria * weight of criteria * impact on implementation platform
int enabled = (Integer.parseInt( Character.toString(crt[z]) ) - correction);
on += ( enabled * criteria[z][0] * criteria[z][1]); oh += ( enabled * criteria[z][0] * criteria[z][2]);
ow += ( enabled * criteria[z][0] * criteria[z][3]); }
//System.out.println(cr + " == "+ on + " " + oh + " "+ ow ); // analyse and process the score for this sequence of criteria analyseResult(on,oh,ow, ec);
}
/** function analyseResult :: compares the scores per platform and decides which has the highest score
* @param on : OutcomeNative , the score of the native platform * @param oh : OutcomeHybrid , the score of the hybrid platform * @param ow : OutComeWeb , the score of the web platform * @param ec : EnabledCriteria , the amount of enabled criteria */
public void analyseResult(int on, int oh, int ow, int ec){ // process normal results
if(on > oh && on > ow){outcomeNative++;} // native has highest
score
else {
if(oh > on && oh > ow){outcomeHybrid++;} // hybrid has highest score
else{
if(ow > on && ow > oh){outcomeWeb++;} // web has highest
score
else{
// there is no highest, so it is undecided outcomeUndecided++;
} } }
outcomeTotal++; // check if all
possibilities are checked (double check feature) // process if minimum amount is satisfied if(ec >= minimumCriteria){
if(on > oh && on > ow){outcomeNativeMC++;} // native has
highest score
else {
if(oh > on && oh > ow){outcomeHybridMC++;} // hybrid has
highest score
else{
if(ow > on && ow > oh){outcomeWebMC++;} // web has
highest score
else{
// there is no highest, so it is undecided outcomeUndecidedMC++;
} } }
outcomeTotalMC++; //
check if all possibilities are checked (double check feature) }
}
// print the stats public void stats(){
System.out.println("Total amount of criteria: " + criteria.length); System.out.println("Total amount of combinations: " + outcomeTotal);
System.out.println("Favor Native: " + outcomeNative); System.out.println("Favor Hybrid: " + outcomeHybrid); System.out.println("Favor Web: " + outcomeWeb); System.out.println("No Favor: " + outcomeUndecided); if(minimumCriteria > 0){
System.out.println("");
System.out.println("Now with minimum of " + minimumCriteria + " criteria (total of: " + criteria.length + ")");
System.out.println("Total amount of combinations: " + outcomeTotalMC + " (total of: " + outcomeTotal + ")");
System.out.println("Favor Native: " + outcomeNativeMC + " (total of: " + outcomeNative + ")");
System.out.println("Favor Hybrid: " + outcomeHybridMC + " (total of: " + outcomeHybrid + ")");
System.out.println("Favor Web: " + outcomeWebMC + " (total of: " + outcomeWeb + ")");
System.out.println("No Favor: " + outcomeUndecidedMC + " (total of: " + outcomeUndecided + ")");
} } /**
* public method main :: Starts the application * @param args
* @return void */
public static void main(String[] args){
System.out.println("SA: Starting Application"); // print to console that program starts
SA analysis = new SA(); analysis.run();
System.out.println("SA: Ending Application"); // print to console that program starts
} // end main }