mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-14 07:17:13 -04:00
Merge branch 'optimizeThreads'
This commit is contained in:
commit
8d1b34cc5b
@ -78,4 +78,9 @@ public class BoolTableExpanded implements BoolTable {
|
||||
public ArrayList<Variable> getVars() {
|
||||
return vars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int realSize() {
|
||||
return e.realSize();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ public class BuilderExpressionCreator {
|
||||
el = new ExpressionListenerOptimizeJK(el);
|
||||
|
||||
expressions.replayTo(el);
|
||||
el.close();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,6 @@ public class ExpressionListenerStore implements ExpressionListener {
|
||||
|
||||
for (Result r : results)
|
||||
listener.resultFound(r.name, r.expression.copy());
|
||||
listener.close();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user