Commit de36af77 authored by Falko Schumann's avatar Falko Schumann 💩
Browse files

Logischer Wert ist nur noch ein Wrapper für `boolean`

... nicht mehr für `boolean` und `double`.
parent 3f32f9e1
Loading
Loading
Loading
Loading
+51 −192
Original line number Diff line number Diff line
@@ -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,220 +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.";

		// Anzahl der Operanden und Operation prüfen
		boolean anzahlOk = false;
		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:
		}

		if (UND.equals(operator) || ODER.equals(operator)) {
			if (operanden.size() >= 2) {
				anzahlOk = true;
			}
		}

		// Alle Operanden müssen ein logischer Wert sein
		boolean typOk = true;
		for (final Object obj : operanden) {
			if (!(obj instanceof LogischerWert)) {
				typOk = false;
				break;
			}
		}

		boolean anzahlOk = validiereAnzahl(operator, operanden);
		boolean typOk = validiereTyp(operanden);
		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);
	}

	/**
	 * 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());
	}

	/**
	 * 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();
	private static boolean validiereAnzahl(Operator operator, List<?> operanden) {
		if (UND.equals(operator) || ODER.equals(operator)) {
			return operanden.size() >= 2;
		} else if (NICHT.equals(operator)) {
			return operanden.size() == 1;
		} else if (IMPLIKATION.equals(operator)) {
			return operanden.size() == 2;
		} else {
			if (operand.getZugehoerigkeit() > wert) {
				wert = operand.getZugehoerigkeit();
			return false;
		}
	}
		}

		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);
	private static boolean validiereTyp(List<?> operanden) {
		return operanden.stream()
				.map(o -> o instanceof LogischerWert)
				.reduce(Boolean::logicalAnd)
				.orElse(false);
	}

		return new LogischerWert(wert);
	protected LogischerWert und(LogischerWert... operanden) {
		return und(Arrays.asList(operanden));
	}

	/**
	 * 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;
	protected LogischerWert und(Collection<LogischerWert> operanden) {
		return operanden.stream()
				.map(LogischerWert::get)
				.reduce(Boolean::logicalAnd)
				.map(LogischerWert::of)
				.get();
	}

			if (operand.getZugehoerigkeit() < wert) {
				wert = operand.getZugehoerigkeit();
	protected LogischerWert oder(LogischerWert... operanden) {
		return oder(Arrays.asList(operanden));
	}
		}
		}

		if (boolWert) {
			// XXX assert eventuell anders verwenden
			assert wert != null && (wert == 1 || wert == 0);

			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);
	}

}
+5 −7
Original line number Diff line number Diff line
@@ -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);
		}
+22 −185
Original line number Diff line number Diff line
@@ -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;
	public static final LogischerWert of(final boolean wert) {
		return wert ? WAHR : FALSCH;
	}
		return 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();
	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;
	}

	/**
	 * 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;
	}

	/**
	 * 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;
	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";
	}

}
+3 −17
Original line number Diff line number Diff line
@@ -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;
	}

	/**
+1 −1
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ public final class TestInterpreter {

        LogischerWert wert = (LogischerWert) ausdruck.interpret(kontext);

        assertTrue(wert.getBoolWert());
        assertTrue(wert.get());
    }

}