...
 
Commits (9)
......@@ -26,7 +26,7 @@
package de.bsvrz.sys.funclib.bitctrl.interpreter.logik;
import java.util.List;
import java.util.*;
import com.bitctrl.i18n.Messages;
......@@ -44,13 +44,13 @@ import de.bsvrz.sys.funclib.bitctrl.interpreter.Operator;
*/
public class LogikHandler extends Handler {
/** Konjunktion bzw. logisches "und" */
/** Logisches "und" */
public static final Operator UND = Operator.getOperator("und");
/** Disjunktion bzw. logisches "oder" */
/** Logisches "oder" */
public static final Operator ODER = Operator.getOperator("oder");
/** Negation bzw. logisches "nicht" */
/** Logisches "nicht" */
public static final Operator NICHT = Operator.getOperator("nicht");
/** Logische Implikation. */
......@@ -68,227 +68,79 @@ public class LogikHandler extends Handler {
@Override
public Object perform(Operator operator, List<?> operanden) {
if (operator == null
|| !validiereHandler(operator, operanden).isValid()) {
throw new InterpreterException(
Messages.get(InterpreterMessages.HandlerNotFound));
if (operator == null || !validiereHandler(operator, operanden).isValid()) {
throw new InterpreterException(Messages.get(InterpreterMessages.HandlerNotFound));
}
LogischerWert result = null;
if (operator == UND) {
result = minimum(operanden.toArray());
return und(operanden.toArray(new LogischerWert[0]));
} else if (operator == ODER) {
result = maximum(operanden.toArray());
return oder(operanden.toArray(new LogischerWert[0]));
} else if (operator == NICHT) {
result = komplement(operanden.get(0));
return nicht((LogischerWert) operanden.get(0));
} else if (operator == IMPLIKATION) {
result = implikation(operanden.toArray());
return implikation((LogischerWert) operanden.get(0), (LogischerWert) operanden.get(1));
}
return result;
throw new IllegalStateException("[unreachable code] unbekannter Operator: " + operator);
}
@Override
public HandlerValidation validiereHandler(Operator operator, List<?> operanden) {
assert operanden != null : "Liste der Operanden darf nicht null sein.";
boolean anzahlOk = false;
boolean typOk = true;
// Anzahl der Operanden und Operation prüfen
switch (operanden.size()) {
case 0:
anzahlOk = false;
break;
case 1:
if (NICHT.equals(operator)) {
anzahlOk = true;
}
break;
case 2:
if (IMPLIKATION.equals(operator)) {
anzahlOk = true;
}
break;
default:
}
boolean anzahlOk = validiereAnzahl(operator, operanden);
boolean typOk = validiereTyp(operanden);
return new HandlerValidation(anzahlOk, typOk);
}
private static boolean validiereAnzahl(Operator operator, List<?> operanden) {
if (UND.equals(operator) || ODER.equals(operator)) {
if (operanden.size() >= 2) {
anzahlOk = true;
}
}
// Alle Operanden müssen ein logischer Wert sein
for (final Object obj : operanden) {
if (obj instanceof LogischerWert) {
final LogischerWert lw = (LogischerWert) obj;
if (!lw.isBoolWert()) {
typOk = false;
break;
}
} else {
typOk = false;
break;
}
return operanden.size() >= 2;
} else if (NICHT.equals(operator)) {
return operanden.size() == 1;
} else if (IMPLIKATION.equals(operator)) {
return operanden.size() == 2;
} else {
return false;
}
return new HandlerValidation(anzahlOk, typOk);
}
/**
* Bestimmt das Ergebnis der Implikation: nicht a oder b.
*
* @param operanden
* Operandenliste mit genau zwei Operanden: a und b
* @return Logischer Wert mit berechneter Zugeh&ouml;rigkeit oder booleschen
* Wert, wenn alle Operanden boolesche Werte haben
*/
protected LogischerWert implikation(final Object[] operanden) {
assert operanden != null : "Argument operanden darf nicht null sein.";
assert operanden.length == 2 : "Anzahl der Operanden muss gleich 2 sein.";
assert operanden[0] instanceof LogischerWert : "Operanden müssen logische Werte sein.";
assert operanden[1] instanceof LogischerWert : "Operanden müssen logische Werte sein.";
final LogischerWert na = komplement(operanden[0]);
final LogischerWert[] ab = { na, (LogischerWert) operanden[1] };
return maximum(ab);
private static boolean validiereTyp(List<?> operanden) {
return operanden.stream()
.map(o -> o instanceof LogischerWert)
.reduce(Boolean::logicalAnd)
.orElse(false);
}
/**
* Berechnet das Komplement: 1 - a. Entspricht dem logischen "nicht".
*
* @param operand
* Operand
* @return Logischer Wert mit berechneter Zugeh&ouml;rigkeit oder booleschen
* Wert, wenn alle Operanden boolesche Werte haben
*/
protected LogischerWert komplement(final Object operand) {
assert operand != null : "Argument operand darf nicht null sein.";
assert operand instanceof LogischerWert : "Operand muss ein logische Werte sein.";
final LogischerWert wert = (LogischerWert) operand;
if (wert.isBoolWert()) {
return new LogischerWert(!wert.getBoolWert());
}
if (wert.getZugehoerigkeit() == null) {
return new LogischerWert(null);
}
final Double d = Math.abs(1.0 - wert.getZugehoerigkeit());
return new LogischerWert(d.floatValue());
protected LogischerWert und(LogischerWert... operanden) {
return und(Arrays.asList(operanden));
}
/**
* Bestimmt das Maximum: max(a, b, ...). Entspricht dem logischen "oder".
*
* @param operanden
* Operandenliste mit mindestens einem Operanden
* @return Logischer Wert mit berechneter Zugeh&ouml;rigkeit oder booleschen
* Wert, wenn alle Operanden boolesche Werte haben
*/
protected LogischerWert maximum(final Object[] operanden) {
assert operanden != null : "Argument operanden darf nicht null sein.";
assert operanden.length > 0 : "Anzahl der Operanden muss größer 0 sein.";
Float wert = null;
boolean boolWert = true;
for (final Object obj : operanden) {
assert obj instanceof LogischerWert : "Operanden müssen logische Werte sein.";
LogischerWert operand;
operand = (LogischerWert) obj;
if (!operand.isBoolWert()) {
boolWert = false;
if (operand.getZugehoerigkeit() == null) {
// Einer der Operanden ist null => Ergebnis = null
return new LogischerWert(null);
}
}
if (wert == null) {
// Erster Operand
wert = operand.getZugehoerigkeit();
} else {
if (operand.getZugehoerigkeit() > wert) {
wert = operand.getZugehoerigkeit();
}
}
}
if (boolWert) {
// XXX assert eventuell entfernen
assert (wert != null) && (wert == 1 || wert == 0);
if (wert != null && wert == 1) {
return new LogischerWert(true);
}
return new LogischerWert(false);
}
return new LogischerWert(wert);
protected LogischerWert und(Collection<LogischerWert> operanden) {
return operanden.stream()
.map(LogischerWert::get)
.reduce(Boolean::logicalAnd)
.map(LogischerWert::of)
.get();
}
/**
* Bestimmt das Minimum: min(a, b, ...). Entspricht dem logischen "und".
*
* @param operanden
* Operandenliste mit mindestens einem Operanden
* @return Logischer Wert mit berechneter Zugeh&ouml;rigkeit oder booleschen
* Wert, wenn alle Operanden boolesche Werte haben
*/
protected LogischerWert minimum(final Object[] operanden) {
assert operanden != null : "Argument operanden darf nicht null sein.";
assert operanden.length > 0 : "Anzahl der Operanden muss größer 0 sein.";
Float wert = null;
boolean boolWert = true;
for (final Object obj : operanden) {
assert obj instanceof LogischerWert : "Operanden müssen logische Werte sein.";
LogischerWert operand;
operand = (LogischerWert) obj;
if (!operand.isBoolWert()) {
boolWert = false;
if (operand.getZugehoerigkeit() == null) {
// Einer der Operanden ist null => Ergebnis = null
return new LogischerWert(null);
}
}
if (wert == null) {
// Erster Operand
wert = operand.getZugehoerigkeit();
} else {
if (operand.getZugehoerigkeit() == null) {
wert = null;
break;
}
if (operand.getZugehoerigkeit() < wert) {
wert = operand.getZugehoerigkeit();
}
}
}
if (boolWert) {
// XXX assert eventuell anders verwenden
assert wert != null && (wert == 1 || wert == 0);
protected LogischerWert oder(LogischerWert... operanden) {
return oder(Arrays.asList(operanden));
}
if (wert != null && wert == 1) {
return new LogischerWert(true);
}
protected LogischerWert oder(Collection<LogischerWert> operanden) {
return operanden.stream()
.map(LogischerWert::get)
.reduce(Boolean::logicalOr)
.map(LogischerWert::of)
.get();
}
return new LogischerWert(false);
}
protected LogischerWert nicht(LogischerWert a) {
return LogischerWert.of(!a.get());
}
return new LogischerWert(wert);
protected LogischerWert implikation(LogischerWert a, LogischerWert b) {
return oder(nicht(a), b);
}
}
......@@ -33,11 +33,11 @@ import de.bsvrz.sys.funclib.bitctrl.interpreter.Kontext;
import de.bsvrz.sys.funclib.bitctrl.interpreter.Variable;
/**
* Ein boolesches Terminalsymbol (Variable).
* Eine Variable die einen logischen Wert enthält.
*
* @author BitCtrl Systems GmbH, Schumann
*/
public class LogischesSymbol implements Variable {
public class LogischeVariable implements Variable<LogischerWert> {
/**
* Der Name der Variable im Kontext.
......@@ -50,7 +50,7 @@ public class LogischesSymbol implements Variable {
* @param name
* Name der Variable im Kontext
*/
public LogischesSymbol(final String name) {
public LogischeVariable(String name) {
Kontext.pruefeName(name);
this.name = name;
}
......@@ -59,7 +59,7 @@ public class LogischesSymbol implements Variable {
* Gibt immer {@code null} zur&uuml;ck, da dies ein Terminalsymbol ist.
*/
@Override
public List<Ausdruck> getNachfolger() {
public List<Ausdruck<?>> getNachfolger() {
return null;
}
......@@ -70,13 +70,11 @@ public class LogischesSymbol implements Variable {
*/
@Override
public String getName() {
assert name != null && name != ""; //$NON-NLS-1$
return name;
}
@Override
public Object interpret(final Kontext kontext) {
public LogischerWert interpret(Kontext kontext) {
if (kontext.enthaelt(getName())) {
return kontext.get(getName(), LogischerWert.class);
}
......
......@@ -31,213 +31,50 @@ import com.bitctrl.i18n.Messages;
import de.bsvrz.sys.funclib.bitctrl.interpreter.InterpreterException;
import de.bsvrz.sys.funclib.bitctrl.interpreter.InterpreterMessages;
import java.util.*;
/**
* Der Wert eines LogischenAsudrucks, der f&uuml;r Boolesche Logik und
* Fuzzy-Logik verwendbar ist. Boolsche Logik wird intern durch die
* Zugeh&ouml;rigkeitswerte "1" und "0" repr&auml;sentiert.
* Wertobjekt für einen booleschen Wert.
*
* @author BitCtrl Systems GmbH, Peuker
* @author BitCtrl Systems GmbH, Schumann
* @author BitCtrl Systems GmbH, Uwe Peuker
* @author BitCtrl Systems GmbH, Falko Schumann
*/
public class LogischerWert {
public final class LogischerWert {
/**
* Eine globale Instanz f&uuml;r den boolschen Wert <i>true</i>.
*/
public static final LogischerWert WAHR = new LogischerWert(true);
/**
* Eine globale Instanz f&uuml;r den boolschen Wert <i>false</i>.
*/
public static final LogischerWert FALSCH = new LogischerWert(false);
/**
* liefert die statische Instanz eines logischen Wertes f&uuml;r die
* Boolschen Werte WAHR und FALSCH.
*
* @param wert
* der boolsche Wert.
* @return die Instanz.
*/
public static final LogischerWert valueOf(final boolean wert) {
if (wert) {
return WAHR;
}
return FALSCH;
public static final LogischerWert of(final boolean wert) {
return wert ? WAHR : FALSCH;
}
/**
* Die Zugeh&ouml;rigkeit.
*/
private Float zugehoerigkeit;
/**
* Gibt an, ob der Wert gerade ein logischer oder ein
* Zugeh&ouml;rigkeitswert ist.
*/
private boolean boolWert;
private final boolean wert;
/**
* Der Konstruktor erzeugt einen logischen Wert mit der Zugeh&ouml;rigkeit
* "1" f&uuml;r <i>true</i> bzw "0" f&uuml;r <i>false</i>.
*
* @param wert
* Der boolsche Wert, den der logische Wert repr&auml;sentieren
* soll
*/
public LogischerWert(final boolean wert) {
set(wert);
private LogischerWert(boolean wert){
this.wert = wert;
}
/**
* Der Konstruktor erzeugt einen logischen Wert mit der &uuml;bergebenen
* Zugeh&ouml;rigkeit.
*
* @param wert
* Der Zugeh&ouml;rigkeitswert
*/
public LogischerWert(final Float wert) {
set(wert);
public boolean get() {
return wert;
}
@Override
public int hashCode() {
throw new UnsupportedOperationException();
}
/**
* Zwei logische Werte sind gleich, wenn sie beide den selben Typ (logischer
* Wert oder Zugeh&ouml;rigkeit) und Wert besitzen.
*/
@Override
public boolean equals(final Object obj) {
if (obj instanceof LogischerWert) {
final LogischerWert lw = (LogischerWert) obj;
Float f1, f2;
f1 = zugehoerigkeit;
f2 = lw.zugehoerigkeit;
if (!(boolWert ^ lw.boolWert) && f1.equals(f2)) {
return true;
}
}
return false;
}
/**
* Gibt den aktuellen Wert zur&uuml;ck.
*
* @return Wert vom Typ {@code Float} oder {@code Boolean}
*/
public Object get() {
if (!boolWert) {
return zugehoerigkeit;
}
assert zugehoerigkeit == 0 || zugehoerigkeit == 1;
if (getZugehoerigkeit() == 1) {
return true;
}
return false;
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LogischerWert that = (LogischerWert) o;
return wert == that.wert;
}
/**
* Liefert einen booleschen Wert entsprechend der Zugeh&ouml;rigkeit des
* logischen Wertes. Die Zugeh&ouml;rigkeit "1" entspricht dem booleschen
* Wert <i>true</i>, die Zugeh&ouml;rigkeit "0" entspricht dem booleschen
* Wert <i>false</i>. Hat die Zugeh&ouml;rigkeit einen anderen Wert wird
* eine <b>InterpreterException</b> geworfen.
*
* @return Den Wert
*/
public boolean getBoolWert() {
if (!boolWert) {
throw new InterpreterException(
Messages.get(InterpreterMessages.NoBooleanValue));
}
assert zugehoerigkeit == 0 || zugehoerigkeit == 1;
if (getZugehoerigkeit() == 1) {
return true;
}
return false;
}
/**
* Liefert den Zugeh&ouml;rigkeitswert, der durch den logischen Wert
* repr&auml;sentiert wird.
*
* @return Wert
*/
public Float getZugehoerigkeit() {
return zugehoerigkeit;
}
/**
* Pr&uuml;ft ob der logische Wert ein boolescher Wert ist.
*
* @return {@code true}, wenn der Wert ein boolescher Wert ist, sonst
* {@code false}
*/
public boolean isBoolWert() {
return boolWert;
}
/**
* Setzt den Wert auf den angegebenen booleschen Wert.
*
* @param wert
* boolescher Wert
*/
public void set(final boolean wert) {
if (wert) {
set(1f);
} else {
set(0f);
}
boolWert = true;
}
/**
* Setzt den Wert auf die angegebene Zugeh&ouml;rigkeit.
*
* @param z
* Zugeh&ouml;rigkeit.
*/
public void set(final Float z) {
if (z != null && (z < 0 || z > 1)) {
throw new InterpreterException(Messages.get(
InterpreterMessages.BadMembership, z));
}
zugehoerigkeit = z;
boolWert = false;
@Override
public int hashCode() {
return Objects.hash(wert);
}
/**
* Wenn der logische Wert ein boolescher Wert ist, wird "wahr" oder "falsch"
* zur&uuml;ckgegeben, sonst der Zahlenwert der Zugeh&ouml;rigkeit.
*/
@Override
public String toString() {
String result;
if (boolWert) {
if (getBoolWert()) {
result = "wahr";
} else {
result = "falsch";
}
} else {
result = String.valueOf(getZugehoerigkeit());
}
return result;
return wert ? "wahr" : "falsch";
}
}
......@@ -33,7 +33,7 @@ import de.bsvrz.sys.funclib.bitctrl.interpreter.Kontext;
import de.bsvrz.sys.funclib.bitctrl.interpreter.Literal;
/**
* Ein boolesches Terminalsymbol (Literal).
* Ein Literal das einen logischen Wert enthält.
*
* @author BitCtrl Systems GmbH, Falko Schumann
*/
......@@ -51,17 +51,7 @@ public class LogischesLiteral implements Literal<LogischerWert> {
* Wert
*/
public LogischesLiteral(final boolean wert) {
this.wert = new LogischerWert(wert);
}
/**
* Konstruiert ein Terminalsymbol mit dem angegebenen Wert.
*
* @param wert
* Wert
*/
public LogischesLiteral(final Float wert) {
this.wert = new LogischerWert(wert);
this.wert = LogischerWert.of(wert);
}
/**
......@@ -71,11 +61,7 @@ public class LogischesLiteral implements Literal<LogischerWert> {
* Wert
*/
public LogischesLiteral(final LogischerWert wert) {
if (wert.isBoolWert()) {
this.wert = new LogischerWert(wert.getBoolWert());
} else {
this.wert = new LogischerWert(wert.getZugehoerigkeit());
}
this.wert = wert;
}
/**
......
......@@ -51,7 +51,7 @@ public final class TestInterpreter {
LogischerWert wert = (LogischerWert) ausdruck.interpret(kontext);
assertTrue(wert.getBoolWert());
assertTrue(wert.get());
}
}