/*
* Copyright Jan 15, 2010 John T. Langton
* email: jlangton at visitrend dot com
* www.visitrend.com
*
* License: GPLv2 or (at your option) any later GPL version
*
* This file is part of NDVis.
*
* 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 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* There should be a copy of the GNU General Public License applied to
* NDVis in the file "NDVis-license" in the folder "license". If not, see
* <http://www.gnu.org/licenses/> or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package com.visitrend.ndvis.optimize;
import java.util.ArrayList;
import com.visitrend.ndvis.app.NDVis;
import com.visitrend.ndvis.colormapper.ColorMapper;
import com.visitrend.ndvis.colormapper.util.ColorEngine;
import com.visitrend.ndvis.gui.spi.DataVisualization;
import org.visitrend.ndvis.parameters.Parameters;
import org.visitrend.ndvis.parameters.ParametersUtils;
/**
* Extremely basic "optimizer" for finding good dimension orders.
*
* @author John T. Langton - jlangton at visitrend dot com
*
*/
public class Optimizer {
// TODO - really have to soup up optimization options. Could try GAs or PCA
// or even basic association rules to determine the dimensions that most
// strongly determine values in other dimensions and then use those as the
// axis dimensions
public Optimizer() {
}
public static short[] flipOptimize(NDVis view) {
DataVisualization dataVis = view.getActiveDataVisualization();
ColorEngine engine = dataVis.getLookup().lookup(ColorMapper.class).getEngine();
// TODO: why are you getting the number of parameters on X from the
// color engine instead of parameters?
int numParametersOnX = dataVis.getLookup().lookup(Parameters.class).getNumParametersOnX();
int[] rgb = engine.getPixels();
int[] rgbCopy = new int[rgb.length];
short[] currentOrder = engine.getCurrentOrder();
short[] bestOrder = PermutorCombinator.cloneShorts(engine.getCurrentOrder());
// I leave this as being a local reference to bases because the user may
// actually set a different value while this processing is happening
short[] bases = view.getDataInfoForVisualization(
dataVis).getBases();
ParametersUtils paramUtils = dataVis.getLookup().lookup(Parameters.class).getParametersUtils();
// score the current image
int score = Score0.score(paramUtils, currentOrder, numParametersOnX,
rgb, Integer.MAX_VALUE);
int bestScore = score;
short[] candidate = null;
boolean keepgoing = true;
// int j = 0;
while (keepgoing) {
if (bestScore == 0) {
return bestOrder;
}
// j += 1;
// System.out.println("Front of while and bestScore is " + bestScore
// + " and currentOrder is: ");
// PermuterCombinatorTest.printPermutation(currentOrder);
// immediately reset keep going, only keep going if there is
// some score out of the next series of flips that is better
// than the current best score
keepgoing = false;
// get every pair-wise swap of values in bestOrder - i.e. this will
// be bestOrder.length choose 2 short[]s returned in an ArrayList
ArrayList permutations = generateAllPairWiseFlips(bestOrder);
for (int k = 0, n = permutations.size(); k < n; k++) {
candidate = (short[]) permutations.get(k);
// PermuterCombinatorTest.printPermutation(candidate);
// reorder the pixels given the candidate ordering
engine.reorderPixelColors(rgb, rgbCopy, currentOrder,
candidate, bases);
// score the new rgb int[] (in terms of what it would look like
// if used to create an image)
score = Score0.score(paramUtils, candidate, numParametersOnX,
rgbCopy, bestScore);
// System.out.println("Current candidate score is " + score
// + " and bestScore is " + bestScore);
if (score < bestScore) {
// System.out
// .println("we got a better order with a score of: "
// + score + " vs. the bestScore so far of: "
// + bestScore);
// ColorEngine.sync(rgb, rgbCopy);
bestScore = score;
bestOrder = candidate;
// if (j < 5) {
// keepgoing = true;
// }
// break the for loop but not the while
k += n;
}
}
}
System.out.println("finished and returning bestScore of " + bestScore
+ " and best order of: ");
// PermuterCombinatorTest.printPermutation(bestOrder);
/*
* TODO: this is very wasteful here because you've already found the
* best order, and reordered the pixels, so you should be able to pass
* that right into colorEngine or something...or you shouldn't be useing
* 2 int arrays at all.
*/
return bestOrder;
}
/**
* This method makes every pair-wise swap of the values in the
* short[] shorts parameter. Specifically, it determines the shorts.length choose 2
* possible ways of swapping every 2 values in the short[] shorts.
*
* @param shorts
* a parameter ordering
*
* @return an ArrayList of shorts.length-1 simple flips of each parameter
* with the one next to it
*/
private static ArrayList generateAllPairWiseFlips(short[] shorts) {
ArrayList answer = new ArrayList();
for (int k = 0; k < shorts.length; k++) {
for (int j = k + 1; j < shorts.length; j++) {
short[] candidate = PermutorCombinator.cloneShorts(shorts);
PermutorCombinator.swap(k, j, candidate);
answer.add(candidate);
// PermuterCombinatorTest.printPermutation(candidate);
}
}
System.out.println("number of permutations is " + answer.size());
return answer;
}
}