/**
*
*/
package vroom.common.heuristics.alns;
import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import vroom.common.utilities.StatCollector;
import vroom.common.utilities.StatCollector.Label;
import vroom.common.utilities.ToStringComparator;
import vroom.common.utilities.Utilities;
import vroom.common.utilities.callbacks.CallbackBase;
import vroom.common.utilities.callbacks.ICallbackEvent;
import vroom.common.utilities.optimization.IInstance;
import vroom.common.utilities.optimization.ISolution;
/**
* <code>ALNSLogger</code> is a simple logger that can be attached to a an {@link AdaptiveLargeNeighborhoodSearch ALNS}
* to write a simple log of the procedure in various csv files.
* <p>
* Creation date: May 27, 2011 - 4:16:30 PM
*
* @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a
* href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a
* href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a>
* @version 1.0
*/
public class ALNSLogger<S extends ISolution> extends
CallbackBase<AdaptiveLargeNeighborhoodSearch<S>, ALNSEventType> {
/** The default labels for the solution logger */
protected static final Label<?>[] SOL_DEFAULT_LABELS = new Label<?>[] { //
new Label<String>("time", String.class), //
new Label<Long>("elapsed_time", Long.class), //
new Label<Integer>("iteration", Integer.class),//
new Label<String>("event", String.class),//
new Label<Double>("best_sol", Double.class),//
new Label<Double>("current_sol", Double.class),//
new Label<Double>("tmp_sol", Double.class) //
};
/** The default labels for the component logger */
protected static final Label<?>[] COMP_DEFAULT_LABELS = new Label<?>[] { //
new Label<String>("time", String.class), //
new Label<Long>("elapsed_time", Long.class), //
new Label<Integer>("iteration", Integer.class),//
new Label<String>("event", String.class) //
};
private StatCollector mSolCol;
private StatCollector mCompCol;
private List<IDestroy<?>> mDestroyComp;
private List<IRepair<?>> mRepairComp;
private final String mDestDir;
private IInstance mInstance;
private ISolution mSolution;
/**
* Creates a new <code>ALNSLogger</code>
*
* @param destDir
* the destination dir for log files
*/
public ALNSLogger(String destDir) {
super();
mDestDir = destDir;
}
/**
* Register this logger to an ALNS
*
* @param alns
* the ALNS which events will be logged
*/
public void registerToALNS(AdaptiveLargeNeighborhoodSearch<S> alns) {
alns.registerCallback(this, ALNSEventType.STARTED);
alns.registerCallback(this, ALNSEventType.IT_FINISHED);
alns.registerCallback(this, ALNSEventType.COMP_UPDATED);
alns.registerCallback(this, ALNSEventType.FINISHED);
}
@SuppressWarnings("unchecked")
@Override
public void execute(ICallbackEvent<AdaptiveLargeNeighborhoodSearch<S>, ALNSEventType> event) {
ALNSCallbackEvent<S> e = (ALNSCallbackEvent<S>) event;
S best, current, tmp;
String time = String.format("%1$tk:%1$tM:%1$tS", new Date(e.getTimeStamp()));
AdaptiveLargeNeighborhoodSearch<?> alns = e.getSource();
switch (e.getType()) {
case STARTED:
mInstance = (IInstance) e.getParams()[0];
mSolution = (S) e.getParams()[1];
createCollectors(alns);
collectSolStats(e, null, null, null);
collectCompStats(e, null, null, null);
break;
case IT_STARTED:
break;
case DESTROYED:
best = (S) e.getParams()[0];
current = (S) e.getParams()[1];
tmp = (S) e.getParams()[2];
collectSolStats(e, best, current, tmp);
break;
case REPAIRED:
best = (S) e.getParams()[0];
current = (S) e.getParams()[1];
tmp = (S) e.getParams()[2];
collectSolStats(e, best, current, tmp);
break;
case SOL_NEW_BEST:
best = (S) e.getParams()[0];
collectSolStats(e, best, best, best);
break;
case SOL_NEW_CURRENT:
best = (S) e.getParams()[0];
current = (S) e.getParams()[1];
collectSolStats(e, best, current, current);
break;
case SOL_REJECTED:
best = (S) e.getParams()[0];
current = (S) e.getParams()[1];
tmp = (S) e.getParams()[2];
collectSolStats(e, best, current, tmp);
break;
case IT_FINISHED:
best = (S) e.getParams()[0];
current = (S) e.getParams()[1];
tmp = (S) e.getParams()[2];
collectSolStats(e, best, current, tmp);
break;
case COMP_UPDATED:
best = (S) e.getParams()[0];
current = (S) e.getParams()[1];
tmp = (S) e.getParams()[2];
collectCompStats(e, best, current, tmp);
break;
case FINISHED:
best = (S) e.getParams()[1];
collectSolStats(e, best, best, best);
collectCompStats(e, best, best, best);
mSolCol.flush();
mCompCol.flush();
break;
default:
break;
}
}
private void createCollectors(AdaptiveLargeNeighborhoodSearch<?> alns) {
String fileName = String.format("%1$ty%1$tm%1$td_%1$tH-%1$tM_%2$s",
new Date(System.currentTimeMillis()), mInstance.getName());
// Solution logging
// -----------------------------
File solFile = new File(Utilities.getUnifiedOutputFilePath(mDestDir, mInstance.getName(), "sol",
"csv"));
Label<?>[] cust = getAdditionalSolLabels(alns);
Label<?>[] labels = Arrays.copyOf(SOL_DEFAULT_LABELS, SOL_DEFAULT_LABELS.length
+ cust.length);
for (int i = 0; i < labels.length - SOL_DEFAULT_LABELS.length && i < cust.length; i++)
labels[SOL_DEFAULT_LABELS.length + i] = cust[i];
mSolCol = new StatCollector(solFile, false, false, String.format("Instance: %s\nALNS:\n%s",
fileName, alns),//
labels);
// -----------------------------
// Components logging
// -----------------------------
File compFile = new File(Utilities.getUnifiedOutputFilePath(mDestDir, mInstance.getName(), "comp",
"csv"));
// Destroy components
mDestroyComp = new ArrayList<IDestroy<?>>(alns.getDestroyComponents().getComponents());
Collections.sort(mDestroyComp, ToStringComparator.INSTANCE);
// Repair components
mRepairComp = new ArrayList<IRepair<?>>(alns.getRepairComponents().getComponents());
Collections.sort(mRepairComp, ToStringComparator.INSTANCE);
cust = getAdditionalCompLabels(alns);
labels = Arrays
.copyOf(COMP_DEFAULT_LABELS, COMP_DEFAULT_LABELS.length + mDestroyComp.size()
+ mRepairComp.size() + cust.length);
// Copy the components name to labels
int i = COMP_DEFAULT_LABELS.length;
for (IDestroy<?> d : mDestroyComp)
labels[i++] = new Label<Double>(d.getName() + "-w", Double.class, new DecimalFormat(
"###0.000000"));
for (IRepair<?> d : mRepairComp)
labels[i++] = new Label<Double>(d.getName() + "-w", Double.class, new DecimalFormat(
"###0.000000"));
for (Label<?> l : cust)
labels[i++] = l;
// -----------------------------
mCompCol = new StatCollector(compFile, false, false, String.format(
"Instance: %s\nALNS:\n%s", fileName, alns),//
labels);
}
/**
* Creation of an array of custom labels for the solution logger
*
* @param alns
* the ALNS which events will be logged
* @return an array of custom labels
* @see #getAdditionalSolStats(ALNSCallbackEvent)
*/
protected Label<?>[] getAdditionalSolLabels(AdaptiveLargeNeighborhoodSearch<?> alns) {
return new Label<?>[0];
}
/**
* Creation of an array of custom labels for the component logger
*
* @param alns
* the ALNS which events will be logged
* @return an array of custom labels
* @see #getAdditionalSolStats(ALNSCallbackEvent)
*/
protected Label<?>[] getAdditionalCompLabels(AdaptiveLargeNeighborhoodSearch<?> alns) {
return new Label<?>[0];
}
/**
* Collect the basic and custom statistics
*
* @param e
* @param bestSol
* @param currentSol
* @param tmpSol
*/
private void collectSolStats(ALNSCallbackEvent<S> e, S bestSol, S currentSol, S tmpSol) {
String time = String.format("%1$tk:%1$tM:%1$tS", new Date(e.getTimeStamp()));
double bs = bestSol != null ? bestSol.getObjectiveValue() : Double.NaN;
double cs = currentSol != null ? currentSol.getObjectiveValue() : Double.NaN;
double ts = tmpSol != null ? tmpSol.getObjectiveValue() : Double.NaN;
// SOLUTION STATS
Object[] values = new Object[mSolCol.getLabels().length];
int k = 0;
values[k++] = time;
values[k++] = e.getElapsedTime();
values[k++] = e.getCurrentIteration();
values[k++] = e.getDescription();
values[k++] = bs;
values[k++] = cs;
values[k++] = ts;
for (Object o : getAdditionalSolStats(e, bestSol, currentSol, tmpSol))
values[k++] = o;
mSolCol.collect(values);
}
/**
* Collect the basic and custom statistics
*
* @param e
* @param bestSol
* @param currentSol
* @param tmpSol
*/
@SuppressWarnings("unchecked")
private void collectCompStats(ALNSCallbackEvent<S> e, S bestSol, S currentSol, S tmpSol) {
String time = String.format("%1$tk:%1$tM:%1$tS", new Date(e.getTimeStamp()));
// COMPONENTS STATS
Object[] values = new Object[mCompCol.getLabels().length];
int k = 0;
values[k++] = time;
values[k++] = e.getElapsedTime();
values[k++] = e.getCurrentIteration();
values[k++] = e.getDescription();
// values[k++] = bestSol;
// values[k++] = currentSol;
// values[k++] = tmpSol;
for (IDestroy<?> d : mDestroyComp)
values[k++] = e.getSource().getDestroyComponents().getWeight((IDestroy<S>) d);
for (IRepair<?> r : mRepairComp)
values[k++] = e.getSource().getRepairComponents().getWeight((IRepair<S>) r);
for (Object o : getAdditionalCompStats(e))
values[k++] = o;
mCompCol.collect(values);
}
/**
* Get custom statistics on the solution.
*
* @param e
* the logged event
* @param bestSol
* the best sol
* @param currentSol
* the current sol
* @param tmpSol
* the tmp sol
* @return an array containing the additional statistics to be logged
* @see #getAdditionalSolLabels(AdaptiveLargeNeighborhoodSearch)
*/
protected Object[] getAdditionalSolStats(ALNSCallbackEvent<S> e, S bestSol, S currentSol,
S tmpSol) {
return new Object[0];
}
/**
* Get custom statistics on the components
*
* @param e
* the logged event
* @return an array containing the additional statistics to be logged
* @see #getAdditionalSolLabels(AdaptiveLargeNeighborhoodSearch)
*/
protected Object[] getAdditionalCompStats(ALNSCallbackEvent<S> e) {
return new Object[0];
}
}