/*
* Copyright 2006-2007 Columbia University.
*
* This file is part of MEAPsoft.
*
* MEAPsoft is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* MEAPsoft 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 MEAPsoft; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* See the file "COPYING" for the text of the license.
*/
package com.meapsoft.composers;
import gnu.getopt.Getopt;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.Vector;
import com.meapsoft.ChunkDist;
import com.meapsoft.EDLChunk;
import com.meapsoft.EDLFile;
import com.meapsoft.EuclideanDist;
import com.meapsoft.FeatChunk;
import com.meapsoft.FeatFile;
import com.meapsoft.Heap;
import com.meapsoft.MaxHeap;
import com.meapsoft.MinHeap;
import com.meapsoft.ParserException;
/**
* Program that composes an EDL by sorting chunks in featFile based on
* some subset of their features using some distance metric. Sorting
* is done based on distance from the origin in feature space.
*
* @author Ron Weiss (ronw@ee.columbia.edu)
*/
public class SortComposer extends Composer
{
public static String description = "SortComposer sorts the " +
"features in ascending or descending " +
"order. If there are multiple features, " +
"or more than one value per feature, it " +
"sorts according to distance in" +
" Euclidean space.";
String outFileName = "sorted.edl";
FeatFile featFile;
int[] featdim = null;
ChunkDist dist;
boolean reverseSort = false;
boolean debug = false;
boolean normalizeFeatures = true;
public SortComposer(String featFN, String outFN)
{
this(featFN, outFN, new EuclideanDist());
}
public SortComposer(FeatFile featFN, EDLFile outFN)
{
this(featFN, outFN, new EuclideanDist());
}
public SortComposer(String featFN, String outFN, ChunkDist cd)
{
this(new FeatFile(featFN), new EDLFile(outFN), cd);
}
public SortComposer(FeatFile featFN, EDLFile outFN, ChunkDist cd)
{
featFile = featFN;
outFile = outFN;
dist = cd;
featdim = cd.featdim;
if(outFile == null)
outFile = new EDLFile("");
}
public void printUsageAndExit()
{
System.out.println("Usage: SortComposer [-options] features.feat \n\n" +
" where options include:\n" +
" -o output_file the file to write the output to (defaults to sorted.edl)\n" +
" -g debug mode (prints out chunk features on each line of output file)\n" +
" -r sort in reverse order");
printCommandLineOptions('i');
printCommandLineOptions('d');
printCommandLineOptions('c');
System.out.println();
System.exit(0);
}
/**
* SortComposer constructor. Parses command line arguments
*/
public SortComposer(String[] args)
{
if(args.length == 0)
printUsageAndExit();
Vector features = new Vector();
// Parse arguments
String argString = "d:i:o:c:r:g";
featdim = parseFeatDim(args, argString);
dist = parseChunkDist(args, argString, featdim);
parseCommands(args, argString);
Getopt opt = new Getopt("SortComposer", args, argString);
opt.setOpterr(false);
int c = -1;
while ((c =opt.getopt()) != -1)
{
switch(c)
{
case 'o':
outFileName = opt.getOptarg();
break;
case 'r':
reverseSort = true;
break;
case 'g':
debug = true;
break;
case 'd': // already handled above
break;
case 'i': // already handled above
break;
case 'c': // already handled above
break;
case '?':
printUsageAndExit();
break;
default:
System.out.print("getopt() returned " + c + "\n");
}
}
// parse arguments
int ind = opt.getOptind();
if(ind > args.length)
printUsageAndExit();
featFile = new FeatFile(args[args.length-1]);
outFile = new EDLFile(outFileName);
System.out.println("Composing " + outFileName +
" from " + args[args.length-1] + ".");
}
public void setReverseSort(boolean b)
{
reverseSort = b;
}
public void setNormalizeFeatures(boolean b)
{
normalizeFeatures = b;
}
public void setup() throws IOException, ParserException
{
super.setup();
if(!featFile.haveReadFile)
featFile.readFile();
if(featFile.chunks.size() == 0)
throw new ParserException(featFile.filename, "No chunks found");
if(normalizeFeatures)
{
featFile = (FeatFile)featFile.clone();
featFile.normalizeFeatures();
featFile.applyFeatureWeights();
}
progress.setMaximum(featFile.chunks.size());
}
public EDLFile compose()
{
// how many feature dimensions are we using?
int maxdim = 0;
if(featdim != null)
{
for(int x = 0; x < featdim.length; x++)
{
if(featdim[x] > maxdim)
maxdim = featdim[x];
}
}
else
maxdim = ((FeatChunk)featFile.chunks.get(0)).numFeatures();
FeatChunk targetChunk = new FeatChunk("",0,0);
for(int i = 0; i <= maxdim; i++)
//targetChunk.addFeature(0);
targetChunk.addFeature(Integer.MIN_VALUE);
dist.setTarget(targetChunk);
// maintain a set of chunks sorted using dist from targetChunk
Heap chunks = null;
if(reverseSort)
chunks = new MaxHeap(dist);
else
chunks = new MinHeap(dist);
chunks.addAll(featFile.chunks);
NumberFormat fmt = NumberFormat.getInstance();
fmt.setMaximumFractionDigits(3);
double currTime = 0;
while(chunks.size() > 0)
{
FeatChunk match = (FeatChunk)chunks.remove(0);
// turn match chunk into an EDL chunk
EDLChunk nc = new EDLChunk(match, currTime);
if(debug)
{
nc.comment = " # feats = ";
double[] feat = match.getFeatures(featdim);
for(int x = 0; x < feat.length-1; x++)
nc.comment += fmt.format(feat[x]) + ", ";
nc.comment += fmt.format(feat[feat.length-1]);
}
outFile.chunks.add(nc);
currTime += match.length;
progress.setValue(progress.getValue()+1);
}
// outFile now contains some chunks.
outFile.haveReadFile = true;
return outFile;
}
public static void main(String[] args)
{
SortComposer m = new SortComposer(args);
long startTime = System.currentTimeMillis();
m.run();
System.out.println("Done. Took " +
((System.currentTimeMillis() - startTime)/1000.0)
+ "s");
System.exit(0);
}
}