package graphmatcher.test;
import graphmatcher.graph.Graph;
import graphmatcher.gui.LabeledTextField;
import graphmatcher.gui.MatchingOptionPanel;
import graphmatcher.gui.MatchingPanel;
import graphmatcher.helper.GraphLoader;
import graphmatcher.helper.GraphTools;
import graphmatcher.matcher.AbstractMatcher;
import graphmatcher.matcher.MatcherFactory;
import graphmatcher.matcher.MatchingOptions;
import graphmatcher.matcher.MatchingResult;
import graphmatcher.matcher.komatcher.KOSystemGraphMatcher;
import graphmatcher.matcher.shapecontext.ShapeContextGraphMatcher;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.SimpleLayout;
public class GraphMatcherTester extends JFrame {
private static Logger logger = Logger.getRootLogger();
private static NumberFormat numberFormat = NumberFormat.getIntegerInstance();
static {
numberFormat.setMinimumIntegerDigits(5);
}
/* Allgemeine Test_Optionen */
private static final String directory = "6e";
private static final int numberOfGraphsToTest = 15;
private static final int maxNumberOfGraphs = 123;
/*
* simple: 4e:111/1100 6e:96/389 9e:87/329
*
* shape: 4e:111/1100 6e:70/276 9e:70/226
*
* ko: 4e:111/1100
*/
private JDialog dialog;
private JButton startButton, stopButton;
private LabeledTextField patternRotationTextField;
private JSlider slider;
private JProgressBar progressBar, totalProgressBar;
private DefaultTableModel model;
private MatchingOptionPanel matchingOptionPanel;
private ReportingPanel reportingPanel, interpolatedReportingPanel;
private Thread thread;
private boolean stopThread;
private double interpolFactor;
private int _tp, _tn, _fp, _fn, bestPositive;
private long _usedTime = 0;
public GraphMatcherTester() {
setTitle("Verzeichnis: " + directory);
setLayout(new BorderLayout());
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
initComponents();
initActions();
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
int result = JOptionPane.showConfirmDialog(GraphMatcherTester.this, "Wirklich beenden?",
"Programm beenden", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
System.exit(0);
}
}
});
}
private void initComponents() {
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new BorderLayout());
JPanel controlContentPanel = new JPanel();
controlContentPanel.setLayout(new GridLayout(0, 1));
controlContentPanel.setBorder(BorderFactory.createTitledBorder("Control-Panel"));
startButton = new JButton("Start");
controlContentPanel.add(startButton);
stopButton = new JButton("Stop");
stopButton.setEnabled(false);
controlContentPanel.add(stopButton);
patternRotationTextField = new LabeledTextField("Mustergraph Rotation", "180", true);
controlContentPanel.add(patternRotationTextField);
controlContentPanel.add(new JLabel("Anzahl Prozessoren"));
int cpus = Runtime.getRuntime().availableProcessors();
slider = new JSlider(SwingConstants.HORIZONTAL, 1, cpus, cpus);
slider.setPreferredSize(new Dimension(100, slider.getPreferredSize().height));
slider.setSnapToTicks(true);
slider.setPaintLabels(true);
slider.setLabelTable(slider.createStandardLabels(1));
controlContentPanel.add(slider);
controlPanel.add(controlContentPanel, BorderLayout.NORTH);
matchingOptionPanel = new MatchingOptionPanel();
controlPanel.add(matchingOptionPanel, BorderLayout.CENTER);
JPanel reportingMasterPanel = new JPanel(new GridLayout(2, 1));
reportingPanel = new ReportingPanel();
reportingMasterPanel.add(reportingPanel);
interpolatedReportingPanel = new ReportingPanel();
reportingMasterPanel.add(interpolatedReportingPanel);
controlPanel.add(reportingMasterPanel, BorderLayout.SOUTH);
add(controlPanel, BorderLayout.WEST);
model = new DefaultTableModel();
model.addColumn("Zeichen");
model.addColumn("SimpleM.");
model.addColumn("ShapeContextM.");
model.addColumn("KOSystemM.");
final JTable table = new JTable(model);
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int column = table.getSelectedColumn();
int row = table.getSelectedRow();
Object value = model.getValueAt(row, column);
if (!(value instanceof MatchingResult)) {
return;
}
MatchingResult result = (MatchingResult) value;
if (dialog != null) {
dialog.dispose();
}
dialog = new JDialog();
dialog.setLocation(GraphMatcherTester.this.getX() + GraphMatcherTester.this.getWidth(), 0);
MatchingPanel panel = new MatchingPanel();
int size = GraphMatcherTester.this.getHeight();
panel.setPreferredSize(new Dimension(size, size));
panel.setMatchingResult(result);
panel.setOptions(true, false, true);
dialog.add(panel);
dialog.pack();
dialog.setVisible(true);
}
});
table.setCellSelectionEnabled(true);
table.setShowGrid(true);
table.setDefaultRenderer(Object.class, new TesterTableCellRenderer());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
JPanel progressPanel = new JPanel();
progressPanel.setLayout(new GridLayout(2, 1));
progressBar = new JProgressBar(SwingConstants.HORIZONTAL);
progressPanel.add(progressBar);
totalProgressBar = new JProgressBar(SwingConstants.HORIZONTAL);
progressPanel.add(totalProgressBar);
add(progressPanel, BorderLayout.SOUTH);
}
private void initActions() {
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
startButton.setEnabled(false);
patternRotationTextField.setEditable(false);
matchingOptionPanel.setEditable(false);
slider.setEnabled(false);
stopButton.setEnabled(true);
stopThread = false;
thread = new Thread(new MatchingTest());
thread.start();
}
});
stopButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stopThread = true;
stopButton.setEnabled(false);
// startButton.setEnabled(true);
slider.setEnabled(true);
}
});
}
/**
* @param args
*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
}
BasicConfigurator.configure(new ConsoleAppender(new SimpleLayout()));
Logger.getRootLogger().setLevel(Level.INFO);
GraphMatcherTester testGUI = new GraphMatcherTester();
testGUI.pack();
testGUI.setVisible(true);
}
private class MatchingTest implements Runnable {
@Override
public void run() {
Vector<Graph> completeGraphList = GraphLoader.loadGraphs(directory, 2000, 2000);
int numberOfAllGraphs = completeGraphList.size();
int numberOfMatchings = numberOfAllGraphs * (numberOfAllGraphs - 1);
completeGraphList.clear();
Vector<Graph> patternGraphList = GraphLoader.loadGraphs(directory, numberOfGraphsToTest,
maxNumberOfGraphs);
Vector<Graph> templateGraphList = GraphLoader.loadGraphs(directory, maxNumberOfGraphs,
maxNumberOfGraphs);
interpolFactor = (double) numberOfAllGraphs / patternGraphList.size();
logger.info("Anzahl Graphen: " + patternGraphList.size());
progressBar.setMinimum(0);
progressBar.setMaximum(templateGraphList.size() - 1);
progressBar.setStringPainted(true);
totalProgressBar.setMinimum(0);
totalProgressBar.setMaximum(patternGraphList.size());
totalProgressBar.setString("Restzeit wird ermittelt");
totalProgressBar.setStringPainted(true);
int rowIndex = 0;
String directory = "c:/Diplomarbeit/Tests/";
Calendar calendar = GregorianCalendar.getInstance();
String prefix = calendar.get(Calendar.MONTH) + "_" + calendar.get(Calendar.DAY_OF_MONTH) + "_";
prefix += calendar.get(Calendar.HOUR_OF_DAY) + "_" + calendar.get(Calendar.MINUTE) + "_";
MatchingOptions matcherOptions = matchingOptionPanel.getMatchingOptions();
FileWriterContainer matcherContainer = FileWriterContainer.createContainer(directory, prefix
+ matchingOptionPanel.getDefaultFileName(), matcherOptions);
long startTime = System.currentTimeMillis();
_tp = 0;
_tn = 0;
_fp = 0;
_fn = 0;
bestPositive = 0;
long currentUsedTime = 0;
for (int i = 0; i < patternGraphList.size(); i++) {
if (stopThread) {
break;
}
Graph pattern = patternGraphList.get(i);
double rotation = Double.parseDouble(patternRotationTextField.getText());
if (rotation != 0) {
System.out.println("rotiere Graph " + pattern.getName() + " um " + rotation + "�");
GraphTools.transformGraph(pattern, GraphTools.createRotation(rotation));
}
model.addRow(new Vector<String>());
model.setValueAt(pattern.toString(), rowIndex, 0);
_usedTime += matchHelper(pattern, templateGraphList, rowIndex, matcherOptions,
matcherContainer);
currentUsedTime = 2 * _usedTime;
rowIndex++;
long currentTime = System.currentTimeMillis();
long usedTime = currentTime - startTime;
double done = (double) (i + 1) / (double) patternGraphList.size();
long estimatedTime = (long) (usedTime / done);
totalProgressBar.setString("Restzeit: " + ((estimatedTime - usedTime) / 1000) + " s");
totalProgressBar.setValue(i + 1);
reportingPanel.setTP(_tp);
reportingPanel.setFN(_fn);
reportingPanel.setFP(_fp);
reportingPanel.setTN(_tn);
reportingPanel.setRecall((double) _tp / (_tp + _fn));
reportingPanel.setCorrectMatchings((double) bestPositive / (i + 1));
reportingPanel.setMS(currentUsedTime / ((i + 1) * (templateGraphList.size() - 1)));
long __tp = Math.round(_tp * interpolFactor);
interpolatedReportingPanel.setTP(__tp);
long __fn = Math.round(_fn * interpolFactor);
interpolatedReportingPanel.setFN(__fn);
interpolatedReportingPanel.setFP(Math.round(_fp * interpolFactor));
interpolatedReportingPanel.setTN(numberOfMatchings - __tp - __fn);
interpolatedReportingPanel.setRecall((double) _tp / (_tp + _fn));
interpolatedReportingPanel.setCorrectMatchings((double) bestPositive / (i + 1));
interpolatedReportingPanel
.setMS(currentUsedTime / ((i + 1) * (templateGraphList.size() - 1)));
}
totalProgressBar.setString("Fertig");
setVisible(true);
System.out.println();
System.out.println("True Positive: " + _tp);
System.out.println("True Negative: " + _tn);
System.out.println("False Positive: " + _fp);
System.out.println("False Negative: " + _fn);
System.out.println("Recall: " + ((double) _tp / (_tp + _fn)));
System.out.println("Best Positive: " + (100 * (double) bestPositive / patternGraphList.size())
+ "%");
long sumOfTimes = 2 * _usedTime;
System.out.println();
System.out.println("durschn. Dauer: "
+ (sumOfTimes / (patternGraphList.size() * (templateGraphList.size() - 1))) + " ms");
double factor = (double) templateGraphList.size() / patternGraphList.size();
System.out.println("\nInterpolation:");
System.out.println("Anzahl Graphen gesamt: " + templateGraphList.size());
System.out.println("Anzahl getesteter Graphen: " + patternGraphList.size());
System.out.println("Faktor: " + factor);
int tpInterpoliert = (int) (_tp * factor);
System.out.println("True Positive: " + tpInterpoliert);
int tnInterpoliert = (int) (_tn * factor);
System.out.println("True Negative: " + tnInterpoliert);
int exactTestNumber = templateGraphList.size() * (templateGraphList.size() - 1);
System.out.println("False Negative: " + (exactTestNumber - tpInterpoliert - tnInterpoliert));
try {
matcherContainer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private long matchHelper(Graph pattern, Vector<Graph> graphList, int rowIndex,
final MatchingOptions options, final FileWriterContainer fileWriterContainer) {
long startTime = System.currentTimeMillis();
final MatchingResult[] matchingResults = new MatchingResult[graphList.size()];
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
.availableProcessors());
progressBar.setValue(0);
for (int j = 0; j < graphList.size(); j++) {
final int currentJ = j;
Graph template = graphList.get(j);
if (pattern.getName().equals(template.getName())) {
continue;
}
final AbstractMatcher matcher = MatcherFactory.createMatcher(options.getMatcherID(), pattern,
template);
Runnable matchingTask = new Runnable() {
@Override
public void run() {
try {
MatchingResult matchingResult = matcher.match(options);
matchingResults[currentJ] = matchingResult;
synchronized (progressBar) {
progressBar.setValue(progressBar.getValue() + 1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
executorService.submit(matchingTask);
}
try {
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
Arrays.sort(matchingResults, new Comparator<MatchingResult>() {
@Override
public int compare(MatchingResult o1, MatchingResult o2) {
if (o1 == null) {
return 1;
}
if (o2 == null) {
return -1;
}
if (o1.getQuality() > o2.getQuality()) {
return -1;
} else {
return 1;
}
}
});
NumberFormat format = NumberFormat.getInstance();
format.setMinimumFractionDigits(2);
format.setMaximumFractionDigits(2);
System.out.println("Matching Qualities: " + pattern.getName());
boolean bestTemplateIsCorrect = pattern.equalMeaning(matchingResults[0].getTemplate());
if (bestTemplateIsCorrect) {
bestPositive++;
}
int tp = 0, tn = 0, fp = 0, fn = 0;
boolean firstNegativeFound = false;
for (int i = 0; i < matchingResults.length; i++) {
if (matchingResults[i] == null) {
continue;
}
Graph template = matchingResults[i].getTemplate();
double quality = matchingResults[i].getQuality();
boolean equal = pattern.equalMeaning(template);
if (!equal) {
firstNegativeFound = true;
}
// System.out.print(template.getShortName() + " (" +
// format.format(quality) + ") - ");
// if (pattern.getName().equals(template.getName())) {
// System.out.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXX");
// // identischer Graph
// continue;
// }
if (equal) {
if (!firstNegativeFound) {
tp++;
} else {
fn++;
}
} else {
tn++;
}
}
System.out.println();
System.out.println("True Positive: " + tp);
System.out.println("True Negative: " + tn);
System.out.println("False Positive: " + fp);
System.out.println("False Negative: " + fn);
_tp += tp;
_tn += tn;
_fp += fp;
_fn += fn;
int column = 1;
if (options.getMatcherID().equals(ShapeContextGraphMatcher.matcherID)) {
column = 2;
}
if (options.getMatcherID().equals(KOSystemGraphMatcher.matcherID)) {
column = 3;
}
model.setValueAt(matchingResults[0], rowIndex, column);
String patternString = matchingResults[0].getPattern().toString();
String templateString = matchingResults[0].getTemplate().toString();
String result = patternString.substring(0, 5) + " -> " + templateString.substring(0, 5) + ", ";
result += numberFormat.format(matchingResults[0].getMatchingTime()) + " ms";
if (!patternString.substring(0, 4).equalsIgnoreCase(templateString.substring(0, 4))) {
result += " *** FEHLER ***";
fileWriterContainer.addWrongMatching();
}
try {
fileWriterContainer.addMatching(result, matchingResults[0].getMatchingTime());
} catch (IOException e) {
e.printStackTrace();
}
return System.currentTimeMillis() - startTime;
}
}
private static class FileWriterContainer {
private int matchings, wrongMatchings;
private long matchingTime;
private BufferedWriter bufferedWriter;
public FileWriterContainer(File file, MatchingOptions options) throws IOException {
matchings = 0;
wrongMatchings = 0;
matchingTime = 0;
bufferedWriter = new BufferedWriter(new FileWriter(file));
bufferedWriter.write(options.getMatcherID());
bufferedWriter.newLine();
bufferedWriter.write(options.getMatcherOptions());
bufferedWriter.newLine();
bufferedWriter.newLine();
}
public BufferedWriter getWriter() {
return bufferedWriter;
}
public void addMatching(String text, long time) throws IOException {
bufferedWriter.write(text);
bufferedWriter.newLine();
bufferedWriter.flush();
matchings++;
matchingTime += time;
}
public void addWrongMatching() {
wrongMatchings++;
}
public void close() throws IOException {
bufferedWriter.newLine();
bufferedWriter.write("Matchings: " + matchings);
bufferedWriter.newLine();
bufferedWriter.write("Fehler: " + wrongMatchings);
bufferedWriter.newLine();
bufferedWriter
.write("Prozent: " + (1 - (double) wrongMatchings / (double) matchings) * 100 + "%");
bufferedWriter.newLine();
bufferedWriter.write("durchschnittliche Matchingdauer: " + (matchingTime / matchings) + " ms");
bufferedWriter.close();
}
public static FileWriterContainer createContainer(String directory, String name,
MatchingOptions options) {
File file = new File(directory, name);
try {
return new FileWriterContainer(file, options);
} catch (IOException e) {
throw new RuntimeException("Fehler beim Anlegen des Container", e);
}
}
}
}