Merge branch 'optimizeThreads'

This commit is contained in:
hneemann 2019-04-04 14:55:37 +02:00
commit 8d1b34cc5b
9 changed files with 220 additions and 40 deletions

View File

@ -78,4 +78,9 @@ public class BoolTableExpanded implements BoolTable {
public ArrayList<Variable> getVars() {
return vars;
}
@Override
public int realSize() {
return e.realSize();
}
}

View File

@ -21,4 +21,11 @@ public interface BoolTable {
* @return the value
*/
ThreeStateValue get(int i);
/**
* @return the real size of the bool table
*/
default int realSize() {
return size();
}
}

View File

@ -74,6 +74,7 @@ public class BuilderExpressionCreator {
el = new ExpressionListenerOptimizeJK(el);
expressions.replayTo(el);
el.close();
}
/**

View File

@ -6,7 +6,6 @@
package de.neemann.digital.gui.components.table;
import de.neemann.digital.analyse.*;
import de.neemann.digital.analyse.expression.Expression;
import de.neemann.digital.analyse.expression.ExpressionException;
import de.neemann.digital.analyse.expression.Variable;
import de.neemann.digital.analyse.expression.format.FormatterException;
@ -17,7 +16,9 @@ import de.neemann.digital.lang.Lang;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -29,8 +30,10 @@ import java.util.concurrent.TimeUnit;
public class ExpressionCreator {
private static final Logger LOGGER = LoggerFactory.getLogger(ExpressionCreator.class);
private static final int MAX_INPUTS_ALLOWED = 12;
private static final int COMPLEX_VAR_SIZE = 8;
private final TruthTable theTable;
private ProgressListener progressListener;
/**
* Creates a new instance
@ -52,38 +55,57 @@ public class ExpressionCreator {
public void create(ExpressionListener listener) throws ExpressionException, FormatterException, AnalyseException {
final List<Variable> vars = Collections.unmodifiableList(theTable.getVars());
long time = System.currentTimeMillis();
if (theTable.getResultCount() > 100) {
if (theTable.getResultCount() >= 4 && vars.size() > COMPLEX_VAR_SIZE) {
LOGGER.debug("use parallel solvers");
ExecutorService ex = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
ThreadSaveExpressionListener threadListener = new ThreadSaveExpressionListener(listener);
ArrayList<Job> jobs = new ArrayList<>();
for (int table = 0; table < theTable.getResultCount(); table++) {
final int t = table;
final ExpressionListenerStore l = new ExpressionListenerStore(null);
jobs.add(simplify(l, vars, theTable.getResultName(table), theTable.getResult(table))
.setStorage(l));
}
LOGGER.debug("jobs: " + jobs.size());
ArrayList<Job> orderedJobs = new ArrayList<>(jobs);
orderedJobs.sort(Comparator.comparingInt(job -> -job.getComplexity()));
for (Job j : orderedJobs) {
ex.submit(() -> {
try {
simplify(listener, vars, theTable.getResultName(t), theTable.getResult(t));
} catch (ExpressionException | FormatterException | AnalyseException e) {
j.run();
j.close();
} catch (ExpressionException | FormatterException e) {
e.printStackTrace();
}
});
}
ex.shutdown();
try {
ex.awaitTermination(100, TimeUnit.HOURS);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadListener.close();
for (Job j : jobs)
j.getStorage().replayTo(listener);
} else {
for (int table = 0; table < theTable.getResultCount(); table++)
simplify(listener, vars, theTable.getResultName(table), theTable.getResult(table));
listener.close();
simplify(listener, vars, theTable.getResultName(table), theTable.getResult(table)).run();
}
listener.close();
time = System.currentTimeMillis() - time;
LOGGER.debug("time: " + time / 1000.0 + " sec");
if (progressListener != null)
progressListener.complete();
}
private void simplify(ExpressionListener listener, List<Variable> vars, String resultName, BoolTable boolTable) throws AnalyseException, ExpressionException, FormatterException {
private Job simplify(ExpressionListener listener, List<Variable> vars, String resultName, BoolTable boolTable) throws AnalyseException, ExpressionException {
List<Variable> localVars = vars;
if (vars.size()>4) {
if (vars.size() > 4) {
TableReducer tr = new TableReducer(vars, boolTable);
if (tr.canReduce()) {
LOGGER.debug(resultName + " reduced from " + vars.size() + " to " + tr.getVars().size() + " variables (" + tr.getVars() + ")");
@ -97,7 +119,7 @@ public class ExpressionCreator {
listener = new CheckResultListener(listener, localVars, boolTable);
getMinimizer(localVars.size()).minimize(localVars, boolTable, resultName, listener);
return new Job(localVars, boolTable, resultName, listener);
}
private MinimizerInterface getMinimizer(int size) {
@ -108,22 +130,70 @@ public class ExpressionCreator {
}
}
/**
* Sets the progress listener to use
*
* @param progressListener the progress listener
* @return this for chained calls
*/
public ExpressionCreator setProgressListener(ProgressListener progressListener) {
this.progressListener = progressListener;
return this;
}
private final static class ThreadSaveExpressionListener implements ExpressionListener {
/**
* Listener used to monitor the progress
*/
public interface ProgressListener {
/**
* Called if a equation is calculated
*/
void oneCompleted();
/**
* Called if all equations are calculated
*/
void complete();
}
private final class Job {
private final List<Variable> localVars;
private final BoolTable boolTable;
private final String resultName;
private final ExpressionListener listener;
private ExpressionListenerStore storage;
private ThreadSaveExpressionListener(ExpressionListener listener) {
private Job(List<Variable> localVars, BoolTable boolTable, String resultName, ExpressionListener listener) {
this.localVars = localVars;
this.boolTable = boolTable;
this.resultName = resultName;
this.listener = listener;
}
@Override
public synchronized void resultFound(String name, Expression expression) throws FormatterException, ExpressionException {
listener.resultFound(name, expression);
private void run() throws ExpressionException, FormatterException {
LOGGER.debug("start job with complexity " + getComplexity());
long time = System.currentTimeMillis();
getMinimizer(localVars.size()).minimize(localVars, boolTable, resultName, listener);
LOGGER.debug("finished job with complexity " + getComplexity() + ": " + (System.currentTimeMillis() - time) / 1000 + "sec");
if (progressListener != null)
progressListener.oneCompleted();
}
@Override
public synchronized void close() throws FormatterException, ExpressionException {
private int getComplexity() {
return boolTable.realSize();
}
private void close() throws FormatterException, ExpressionException {
listener.close();
}
private ExpressionListenerStore getStorage() {
return storage;
}
private Job setStorage(ExpressionListenerStore storage) {
this.storage = storage;
return this;
}
}
}

View File

@ -62,7 +62,6 @@ public class ExpressionListenerStore implements ExpressionListener {
for (Result r : results)
listener.resultFound(r.name, r.expression.copy());
listener.close();
}
/**

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2019 Helmut Neemann.
* Use of this source code is governed by the GPL v3 license
* that can be found in the LICENSE file.
*/
package de.neemann.digital.gui.components.table;
import de.neemann.digital.lang.Lang;
import de.neemann.gui.Screen;
import javax.swing.*;
import java.awt.*;
/**
* A simple progress dialog which is used by the {@link ExpressionCreator}
*/
public class ProgressDialog extends JDialog implements ExpressionCreator.ProgressListener {
private final JProgressBar bar;
private int prog;
/**
* Create a new instance
*
* @param tableDialog the table dialog
*/
public ProgressDialog(TableDialog tableDialog) {
super(tableDialog, false);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
bar = new JProgressBar(0, tableDialog.getModel().getTable().getResultCount());
int b = Screen.getInstance().getFontSize();
bar.setBorder(BorderFactory.createEmptyBorder(b, b, b, b));
final JLabel label = new JLabel(Lang.get("msg_optimizationInProgress"));
label.setBorder(BorderFactory.createEmptyBorder(b, b, 0, b));
getContentPane().add(label, BorderLayout.NORTH);
getContentPane().add(bar, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(tableDialog);
SwingUtilities.invokeLater(() -> setVisible(true));
}
@Override
public void oneCompleted() {
SwingUtilities.invokeLater(() -> bar.setValue(++prog));
}
@Override
public void complete() {
SwingUtilities.invokeLater(this::dispose);
}
}

View File

@ -5,7 +5,10 @@
*/
package de.neemann.digital.gui.components.table;
import de.neemann.digital.analyse.*;
import de.neemann.digital.analyse.AnalyseException;
import de.neemann.digital.analyse.ModelAnalyserInfo;
import de.neemann.digital.analyse.TruthTable;
import de.neemann.digital.analyse.TruthTableTableModel;
import de.neemann.digital.analyse.expression.Expression;
import de.neemann.digital.analyse.expression.ExpressionException;
import de.neemann.digital.analyse.expression.Variable;
@ -41,6 +44,8 @@ import de.neemann.gui.ErrorMessage;
import de.neemann.gui.MyFileChooser;
import de.neemann.gui.Screen;
import de.neemann.gui.ToolTipAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
@ -61,8 +66,10 @@ import java.util.StringTokenizer;
import java.util.prefs.Preferences;
/**
*
*/
public class TableDialog extends JDialog {
private static final Logger LOGGER = LoggerFactory.getLogger(TableDialog.class);
private static final Preferences PREFS = Preferences.userRoot().node("dig").node("generator");
private static final Color MYGRAY = new Color(230, 230, 230);
private static final List<Key> LIST = new ArrayList<>();
@ -304,6 +311,7 @@ public class TableDialog extends JDialog {
if (createJK.isSelected())
expressionListener = new ExpressionListenerJK(expressionListener);
lastGeneratedExpressions.replayTo(expressionListener);
expressionListener.close();
} catch (ExpressionException | FormatterException e1) {
new ErrorMessage(Lang.get("msg_errorDuringCalculation")).addCause(e1).show(TableDialog.this);
}
@ -584,16 +592,50 @@ public class TableDialog extends JDialog {
private void calculateExpressions() {
try {
LOGGER.info("start optimization");
ExpressionListener expressionListener = new HTMLExpressionListener();
if (createJK.isSelected())
expressionListener = new ExpressionListenerJK(expressionListener);
lastGeneratedExpressions = new ExpressionListenerStore(expressionListener);
new ExpressionCreator(model.getTable()).create(lastGeneratedExpressions);
final TruthTable table = model.getTable();
if (table.getVars().size() >= 8) {
ProgressDialog progress = new ProgressDialog(this);
kvMap.setResult(model.getTable(), lastGeneratedExpressions.getResults());
ExpressionListener finalExpressionListener = expressionListener;
new Thread(() -> {
ExpressionListenerStore storage = new ExpressionListenerStore(null);
try {
new ExpressionCreator(table).setProgressListener(progress).create(storage);
} catch (ExpressionException | FormatterException | AnalyseException e) {
SwingUtilities.invokeLater(() -> {
progress.dispose();
lastGeneratedExpressions = null;
new ErrorMessage(Lang.get("msg_errorDuringCalculation")).addCause(e).show(this);
});
return;
}
SwingUtilities.invokeLater(() -> {
try {
lastGeneratedExpressions = new ExpressionListenerStore(finalExpressionListener);
storage.replayTo(lastGeneratedExpressions);
lastGeneratedExpressions.close();
kvMap.setResult(table, lastGeneratedExpressions.getResults());
} catch (FormatterException | ExpressionException e) {
lastGeneratedExpressions = null;
new ErrorMessage(Lang.get("msg_errorDuringCalculation")).addCause(e).show(this);
}
});
}).start();
} else {
lastGeneratedExpressions = new ExpressionListenerStore(expressionListener);
new ExpressionCreator(table).create(lastGeneratedExpressions);
kvMap.setResult(table, lastGeneratedExpressions.getResults());
}
LOGGER.info("optimization finished");
} catch (ExpressionException | FormatterException | AnalyseException e1) {
lastGeneratedExpressions = null;
new ErrorMessage(Lang.get("msg_errorDuringCalculation")).addCause(e1).show(this);
@ -731,22 +773,24 @@ public class TableDialog extends JDialog {
public void close() {
html.append("</table></html>");
switch (count) {
case 0:
statusBar.setVisible(false);
allSolutionsDialog.setVisible(false);
break;
case 1:
statusBar.setVisible(true);
statusBar.setText(firstExp);
allSolutionsDialog.setVisible(false);
break;
default:
statusBar.setVisible(false);
allSolutionsDialog.setText(html.toString());
if (!allSolutionsDialog.isVisible())
SwingUtilities.invokeLater(() -> allSolutionsDialog.setVisible(true));
}
SwingUtilities.invokeLater(() -> {
switch (count) {
case 0:
statusBar.setVisible(false);
allSolutionsDialog.setVisible(false);
break;
case 1:
statusBar.setVisible(true);
statusBar.setText(firstExp);
allSolutionsDialog.setVisible(false);
break;
default:
statusBar.setVisible(false);
allSolutionsDialog.setText(html.toString());
if (!allSolutionsDialog.isVisible())
allSolutionsDialog.setVisible(true);
}
});
}
}

View File

@ -918,6 +918,7 @@ Es sind nur {1} Variablen erlaubt, es wurden jedoch {2} gefunden.</string>
<string name="err_processExitedWithError_N1_N2">Der Prozess meldet den Rückgabewert {0}: {1}</string>
<string name="err_errorRunningFitter">Fehler beim Starten des externen Fitters!</string>
<string name="err_noExpressionsAvailable">Es liegen keine minimierten Gleichungen vor!</string>
<string name="msg_optimizationInProgress">Gleichungen werden berechnet! Einen Moment Geduld!</string>
<string name="err_varName_N_UsedTwice">Die Variable {0} wird mehrfach verwendet!</string>
<string name="err_fileNeedsToBeSaved">Die Datei muss zunächst gespeichert werden!</string>
<string name="err_recursiveNestingAt_N0">Die Schaltung {0} bindet sich selbst ein!</string>

View File

@ -912,6 +912,7 @@
<string name="err_processExitedWithError_N1_N2">The process returns the non zero value {0}: {1}</string>
<string name="err_errorRunningFitter">Error starting the external fitter!</string>
<string name="err_noExpressionsAvailable">There are no minimized equations!</string>
<string name="msg_optimizationInProgress">Equations are calculated! Please wait a moment!</string>
<string name="err_varName_N_UsedTwice">The variable {0} is used twice!</string>
<string name="err_fileNeedsToBeSaved">The file needs to be saved!</string>
<string name="err_recursiveNestingAt_N0">The circuit {0} imports itself!</string>