diff --git a/src/main/java/org/jreliability/bdd/BDDReliabilityFunction.java b/src/main/java/org/jreliability/bdd/BDDReliabilityFunction.java index 938a80f..f4b09d4 100644 --- a/src/main/java/org/jreliability/bdd/BDDReliabilityFunction.java +++ b/src/main/java/org/jreliability/bdd/BDDReliabilityFunction.java @@ -15,10 +15,18 @@ package org.jreliability.bdd; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import org.apache.commons.collections15.Transformer; +import org.jreliability.booleanfunction.Term; +import org.jreliability.booleanfunction.common.ANDTerm; +import org.jreliability.booleanfunction.common.LiteralTerm; +import org.jreliability.booleanfunction.common.NOTTerm; +import org.jreliability.common.StructureFunction; import org.jreliability.function.ReliabilityFunction; import org.jreliability.function.SequentialFunction; -import org.jreliability.function.UnreliabilityFunction; /** * The {@link BDDReliabilityFunction} represents the {@link ReliabilityFunction} @@ -26,19 +34,18 @@ * * @author glass * - * @param - * the type of variable + * @param the type of variable */ -public class BDDReliabilityFunction extends SequentialFunction implements ReliabilityFunction { +public class BDDReliabilityFunction extends SequentialFunction implements ReliabilityFunction, StructureFunction { /** - * The BDD representing the {@link UnreliabilityFunction}. + * The BDD representing the {@link ReliabilityFunction}. */ protected final BDD bdd; /** - * The used {@link Transformer} to get the {@link ReliabilityFunction} of - * each element of the {@link BDD}. + * The used {@link Transformer} to get the {@link ReliabilityFunction} of each + * element of the {@link BDD}. */ protected final Transformer functionTransformer; @@ -51,12 +58,10 @@ public class BDDReliabilityFunction extends SequentialFunction implements Rel * Constructs a {@link BDDReliabilityFunction} with a given {@link BDD} and * {@link Transformer}. * - * @param bdd - * the bdd representing the reliabilityFunction + * @param bdd the bdd representing the reliabilityFunction * - * @param functionTransformer - * the functionTransformer to transform bdd elements to - * reliabilityFunction + * @param functionTransformer the functionTransformer to transform bdd elements + * to reliabilityFunction */ public BDDReliabilityFunction(BDD bdd, Transformer functionTransformer) { super(); @@ -77,8 +82,7 @@ public double getY(final double x) { /** * Default {@link Transformer}. * - * @param a - * parameter a + * @param a parameter a * @return the double value of a */ @Override @@ -108,4 +112,33 @@ public Transformer getTransformer() { return functionTransformer; } + /* + * (non-Javadoc) + * + * @see org.jreliability.common.StructureFunction#isProvidingService(Map) + */ + @Override + public boolean isProvidingService(Map variables) { + // Convert variables and their phase to a term + List terms = new ArrayList(); + for (Map.Entry entry : variables.entrySet()) { + LiteralTerm literalTerm = new LiteralTerm(entry.getKey()); + if (entry.getValue()) { + terms.add(literalTerm); + } else { + terms.add(new NOTTerm(literalTerm)); + } + } + ANDTerm variablesTerm = new ANDTerm(terms); + // Get BDD from term + BDDTTRF bddTTRF = new BDDTTRF(bdd.getProvider()); + BDD variablesBDD = bddTTRF.convertToBDD(variablesTerm); + + // Combine variablesBDD and bdd via AND: If result is zero, no service is provided anymore + BDD tmpBDD = bdd.copy(); + tmpBDD.andWith(variablesBDD); + boolean hasFailed = tmpBDD.isZero(); + return !hasFailed; + } + } diff --git a/src/main/java/org/jreliability/common/StructureFunction.java b/src/main/java/org/jreliability/common/StructureFunction.java new file mode 100644 index 0000000..dd8b78d --- /dev/null +++ b/src/main/java/org/jreliability/common/StructureFunction.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * JReliability is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * JReliability is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with JReliability. If not, see http://www.gnu.org/licenses/. + *******************************************************************************/ +package org.jreliability.common; + +import java.util.Map; + +/** + * The {@link StructureFunction} {@code phi(T)} is a characteristic or indicator + * function that determines whether the system provides correct service + * ({@code phi(X) = true}) or has failed ({@code phi(X) = false}) given a set of + * properly working and/or failed variables of type T. + * + * @author glass + * + * @param the type of the variables + * + */ +public interface StructureFunction { + + /** + * Corresponds to the structure function {@code phi} and returns whether the + * system works given a map of either working or failed variables + * + * @param variables the map of working or failed variables + * @return true if the system still provides correct service and false in case + * it failed + */ + public boolean isProvidingService(Map variables); + +} diff --git a/src/main/java/org/jreliability/sl/SL.java b/src/main/java/org/jreliability/sl/SL.java index 29a3d38..5ad2e9a 100644 --- a/src/main/java/org/jreliability/sl/SL.java +++ b/src/main/java/org/jreliability/sl/SL.java @@ -30,10 +30,12 @@ import org.jreliability.booleanfunction.common.NOTTerm; import org.jreliability.booleanfunction.common.ORTerm; import org.jreliability.booleanfunction.common.TRUETerm; +import org.jreliability.common.StructureFunction; /** * The {@link SL} uses the concept of stochastic logic [A] to evaluate a given - * {@link Term}. + * {@link Term}. Note that the implementation for {@link StructureFunction} + * works solely for coherent systems. * * [A] Aliee, H. and Zarandi, H.R.. Fault tree analysis using stochastic logic: * A reliable and high speed computing. In Proceedings of the Annual Reliability @@ -41,10 +43,9 @@ * * @author glass, jlee * - * @param - * the type of the variables + * @param the type of the variables */ -public class SL { +public class SL implements StructureFunction { /** * The {@link Term} to be evaluated. @@ -60,8 +61,7 @@ public class SL { */ protected List termsForStackProcessing = new ArrayList<>(); /** - * The number of operands for each term which are then popped from the - * stack. + * The number of operands for each term which are then popped from the stack. */ protected Map numberOfOperands = new HashMap<>(); /** @@ -70,29 +70,33 @@ public class SL { protected Stack operandsStack = new Stack<>(); /** * In stochastic logic, equal variables have to be modeled using exactly the - * same bit stream (since they are actually the same!). This is realized by - * the term cache. + * same bit stream (since they are actually the same!). This is realized by the + * term cache. */ protected Map termCache = new HashMap<>(); + /** + * The length of the bit stream when using the + * {@link StructureFunction} interface. A length of 1 is sufficient for coherent + * systems. + */ + protected int bitStreamLengthStructureFunction = 1; + /** * Constructs an {@link SL} with a given {@link Term}. * - * @param term - * the term to evaluate + * @param term the term to evaluate */ public SL(Term term) { this(term, 10000); } /** - * Constructs an {@link SL} with a given {@link Term} and a given length of - * the bit streams to use. + * Constructs an {@link SL} with a given {@link Term} and a given length of the + * bit streams to use. * - * @param term - * the term to evaluate - * @param bitStreamLength - * the length of the bit streams + * @param term the term to evaluate + * @param bitStreamLength the length of the bit streams */ public SL(Term term, int bitStreamLength) { this.term = term; @@ -104,8 +108,7 @@ public SL(Term term, int bitStreamLength) { * Initializes the {@link SL} by ordering the {@link Term} for the stack * processing. * - * @param term - * the term to initialize + * @param term the term to initialize */ protected void initialize(Term term) { if (term instanceof NOTTerm) { @@ -128,34 +131,42 @@ protected void initialize(Term term) { } /** - * Calculates the probability of the {@link Term} (i.e. the top event) based - * on a given probabilities of the basic events. + * Calculates the probability of the {@link Term} (i.e. the top event) based on + * a given probabilities of the basic events. * - * @param transformer - * the probabilities of the basic events + * @param transformer the probabilities of the basic events * @return the probability of the top event */ public double getProbabiliy(Transformer transformer) { operandsStack.clear(); termCache.clear(); - evaluate(transformer); + evaluateProbability(transformer); // Evaluate leaves the final bit stream of the top event on the stack BitSet bitstream = operandsStack.pop(); double probability = (double) bitstream.cardinality() / bitstream.size(); return probability; } + @Override + public boolean isProvidingService(Map variables) { + operandsStack.clear(); + termCache.clear(); + // Evaluate leaves the final bit stream of the top event on the stack + evaluateStructureFunction(variables); + BitSet bitstream = operandsStack.pop(); + System.err.println(bitstream); + return bitstream.cardinality() > 0; + } + /** * The evaluation performs the actual stochastic logic calculations by a * sequential processing of the different terms according to their order and - * using a stack. Note that this function leaves its current result on the - * stack - eventually, the result for the top event will remain on the - * stack! + * using a stack. Note that this function leaves its current result on the stack + * - eventually, the result for the top event will remain on the stack! * - * @param transformer - * the probability of the basic events + * @param transformer the probability of the basic events */ - protected void evaluate(Transformer transformer) { + protected void evaluateProbability(Transformer transformer) { for (Term term : termsForStackProcessing) { if (term instanceof LiteralTerm) { BitSet bitstream = termCache.get(term); @@ -166,32 +177,78 @@ protected void evaluate(Transformer transformer) { termCache.put(term, bitstream); } operandsStack.push(bitstream); - } else if (term instanceof FALSETerm) { - BitSet bitstream = new BitSet(bitStreamLength); - bitstream.clear(); - operandsStack.push(bitstream); - } else if (term instanceof TRUETerm) { - BitSet bitstream = new BitSet(bitStreamLength); - bitstream.set(0, bitstream.size(), true); + } else { + evaluateNonLiteralTerms(term, bitStreamLength); + } + } + } + + /** + * Evaluates the {@link Term} as SL would, but a bit stream length of 1 + * + * @param variables + */ + protected void evaluateStructureFunction(Map variables) { + for (Term term : termsForStackProcessing) { + if (term instanceof LiteralTerm) { + BitSet bitstream = termCache.get(term); + if (bitstream == null) { + @SuppressWarnings("unchecked") + LiteralTerm component = (LiteralTerm) term; + T variable = component.get(); + bitstream = new BitSet(bitStreamLengthStructureFunction); + // Default: Set all entries to 1 (captures 1 variables and all non-specified + // ones) + // Careful, this only works in coherent systems! + bitstream.set(0, bitstream.size(), true); + // Pull 0 variables to all 0 bit streams + if (variables.containsKey(variable)) { + boolean isFailed = !variables.get(variable); + if (isFailed) { + bitstream.clear(); + } + } + termCache.put(term, bitstream); + } operandsStack.push(bitstream); - } else if (term instanceof ANDTerm) { - evaluateAND(term); - } else if (term instanceof ORTerm) { - evaluateOR(term); - } else if (term instanceof NOTTerm) { - evaluateNOT(term); } else { - throw new IllegalArgumentException("SL does not support terms of class " + term.getClass()); + evaluateNonLiteralTerms(term, bitStreamLengthStructureFunction); } } } /** - * The evaluation of an {@link ANDTerm} with respective AND operation on the - * bit streams of the operands. + * Helper function to process all terms that are not {@link LiteralTerm}s to + * enhance code re-use. + * + * @param term the term to evaluate + * @param bitstreamlength the length of the bit stream + */ + protected void evaluateNonLiteralTerms(Term term, int bitstreamlength) { + if (term instanceof FALSETerm) { + BitSet bitstream = new BitSet(bitStreamLength); + bitstream.clear(); + operandsStack.push(bitstream); + } else if (term instanceof TRUETerm) { + BitSet bitstream = new BitSet(bitStreamLength); + bitstream.set(0, bitstream.size(), true); + operandsStack.push(bitstream); + } else if (term instanceof ANDTerm) { + evaluateAND(term); + } else if (term instanceof ORTerm) { + evaluateOR(term); + } else if (term instanceof NOTTerm) { + evaluateNOT(term); + } else { + throw new IllegalArgumentException("SL does not support terms of class " + term.getClass()); + } + } + + /** + * The evaluation of an {@link ANDTerm} with respective AND operation on the bit + * streams of the operands. * - * @param term - * the ANDTerm to evaluate + * @param term the ANDTerm to evaluate */ protected void evaluateAND(Term term) { int myNumberOfOperands = numberOfOperands.get(term); @@ -211,11 +268,10 @@ protected void evaluateAND(Term term) { } /** - * The evaluation of an {@link ORTerm} with respective OR operation on the - * bit streams of the operands. + * The evaluation of an {@link ORTerm} with respective OR operation on the bit + * streams of the operands. * - * @param term - * the ORTerm to evaluate + * @param term the ORTerm to evaluate */ protected void evaluateOR(Term term) { int myNumberOfOperands = numberOfOperands.get(term); @@ -235,11 +291,10 @@ protected void evaluateOR(Term term) { } /** - * The evaluation of an {@link NOTTerm} with respective flip of the bit - * streams of the operand. + * The evaluation of an {@link NOTTerm} with respective flip of the bit streams + * of the operand. * - * @param term - * the NOTTerm to evaluate + * @param term the NOTTerm to evaluate */ protected void evaluateNOT(Term term) { BitSet operand = operandsStack.pop(); @@ -249,13 +304,12 @@ protected void evaluateNOT(Term term) { } /** - * Generates a {@link BitSet} representing the bit stream where the ratio of - * 1s and 0s resembles the given probability. This implementation does not - * apply this probability on a per-bit basis but considers the bit length - * with respective rounding effects! + * Generates a {@link BitSet} representing the bit stream where the ratio of 1s + * and 0s resembles the given probability. This implementation does not apply + * this probability on a per-bit basis but considers the bit length with + * respective rounding effects! * - * @param probability - * the probability to model with the bit stream + * @param probability the probability to model with the bit stream * @return the bit stream */ protected BitSet generateRandomBitstream(double probability) { @@ -274,4 +328,24 @@ protected BitSet generateRandomBitstream(double probability) { return bitstream; } + /** + * Returns the length of the bitstreams when using the {@link StructureFunction} + * interface. + * + * @return the length of the bitstreams + */ + public int getBitStreamLengthStructureFunction() { + return bitStreamLengthStructureFunction; + } + + /** + * Sets the length of the bitstreams when using the {@link StructureFunction} + * interface. + * + * @param bitStreamLengthStructureFunction the length of the bitstreams + */ + public void setBitStreamLengthStructureFunction(int bitStreamLengthStructureFunction) { + this.bitStreamLengthStructureFunction = bitStreamLengthStructureFunction; + } + } \ No newline at end of file diff --git a/src/main/java/org/jreliability/sl/SLReliabilityFunction.java b/src/main/java/org/jreliability/sl/SLReliabilityFunction.java index 59f39db..8de32c7 100644 --- a/src/main/java/org/jreliability/sl/SLReliabilityFunction.java +++ b/src/main/java/org/jreliability/sl/SLReliabilityFunction.java @@ -25,8 +25,7 @@ * * @author glass, jlee * - * @param - * the type of variable + * @param the type of variable */ public class SLReliabilityFunction extends SequentialFunction implements ReliabilityFunction { @@ -36,8 +35,8 @@ public class SLReliabilityFunction extends SequentialFunction implements Reli protected final SL stochasticLogic; /** - * The used {@link Transformer} to get the {@link ReliabilityFunction} of - * each element of the {@link SL}. + * The used {@link Transformer} to get the {@link ReliabilityFunction} of each + * element of the {@link SL}. */ protected final Transformer functionTransformer; @@ -45,11 +44,10 @@ public class SLReliabilityFunction extends SequentialFunction implements Reli * Constructs a {@link SLReliabilityFunction} with a given {@link SL} and * {@link Transformer}. * - * @param stochasticLogic - * the stochastic logic representing the reliabilityFunction - * @param functionTransformer - * the functionTransformer to transform stochastic logic elements - * to reliabilityFunction + * @param stochasticLogic the stochastic logic representing the + * reliabilityFunction + * @param functionTransformer the functionTransformer to transform stochastic + * logic elements to reliabilityFunction */ public SLReliabilityFunction(SL stochasticLogic, Transformer functionTransformer) { this.stochasticLogic = stochasticLogic; @@ -68,8 +66,7 @@ public double getY(final double x) { /** * Default {@link Transformer}. * - * @param a - * parameter a + * @param a parameter a * @return the double value of a */ @Override diff --git a/src/test/java/org/jreliability/bdd/BDDReliabilityFunctionTest.java b/src/test/java/org/jreliability/bdd/BDDReliabilityFunctionTest.java index ad74748..2914b7b 100644 --- a/src/test/java/org/jreliability/bdd/BDDReliabilityFunctionTest.java +++ b/src/test/java/org/jreliability/bdd/BDDReliabilityFunctionTest.java @@ -15,11 +15,15 @@ package org.jreliability.bdd; +import java.util.HashMap; +import java.util.Map; + import org.apache.commons.collections15.Transformer; import org.jreliability.bdd.javabdd.JBDDProviderFactory; import org.jreliability.booleanfunction.Term; import org.jreliability.booleanfunction.common.ANDTerm; import org.jreliability.booleanfunction.common.LiteralTerm; +import org.jreliability.booleanfunction.common.ORTerm; import org.jreliability.function.ReliabilityFunction; import org.jreliability.function.common.ExponentialReliabilityFunction; import org.junit.jupiter.api.Assertions; @@ -105,4 +109,42 @@ public void testGetTransformer() { Assertions.assertEquals(transformer, function.getTransformer()); } + @Test + public void testIsProvidingService() { + // Sensor 1 & 2 in parallel, sensor 3 in series + String var1 = "sensor1"; + String var2 = "sensor2"; + String var3 = "sensor3"; + Term s1 = new LiteralTerm<>(var1); + Term s2 = new LiteralTerm<>(var2); + Term s3 = new LiteralTerm<>(var3); + ORTerm or = new ORTerm(); + or.add(s1, s2); + ANDTerm and = new ANDTerm(); + and.add(or, s3); + + BDDTTRF ttrf = new BDDTTRF(provider); + BDD bdd = ttrf.convertToBDD(and); + + BDDReliabilityFunction function = new BDDReliabilityFunction(bdd, new TestTransformer()); + + Map failedComponents = new HashMap(); + + // First sensor failure should return proper working system + failedComponents.put(var1, false); + Assertions.assertTrue(function.isProvidingService(failedComponents)); + + // Second sensor failure should return failed system + failedComponents.put(var2, false); + Assertions.assertFalse(function.isProvidingService(failedComponents)); + + // Second sensor back to life, system properly working + failedComponents.put(var2, true); + Assertions.assertTrue(function.isProvidingService(failedComponents)); + + // Sensor 3 failure cannot be mitigated, system fails + failedComponents.put(var3, false); + Assertions.assertFalse(function.isProvidingService(failedComponents)); + } + } diff --git a/src/test/java/org/jreliability/booleanfunction/common/LiteralTermTest.java b/src/test/java/org/jreliability/booleanfunction/common/LiteralTermTest.java index bd88c99..f5d4545 100644 --- a/src/test/java/org/jreliability/booleanfunction/common/LiteralTermTest.java +++ b/src/test/java/org/jreliability/booleanfunction/common/LiteralTermTest.java @@ -44,6 +44,7 @@ public void testEquals() { Assertions.assertFalse(s1.equals(s6)); Assertions.assertFalse(s1.equals(s7)); Assertions.assertFalse(s4.equals(s1)); + Assertions.assertFalse(s2.equals("2")); } @Test diff --git a/src/test/java/org/jreliability/sl/SLTest.java b/src/test/java/org/jreliability/sl/SLTest.java index 8db864c..b18acc2 100644 --- a/src/test/java/org/jreliability/sl/SLTest.java +++ b/src/test/java/org/jreliability/sl/SLTest.java @@ -14,7 +14,11 @@ *******************************************************************************/ package org.jreliability.sl; +import java.util.HashMap; +import java.util.Map; + import org.apache.commons.collections15.Transformer; +import org.jreliability.booleanfunction.Term; import org.jreliability.booleanfunction.common.ANDTerm; import org.jreliability.booleanfunction.common.FALSETerm; import org.jreliability.booleanfunction.common.LinearTerm; @@ -184,4 +188,54 @@ public ReliabilityFunction transform(String input) { }); } + @Test + public void testIsProvidingService() { + // Sensor 1 & 2 in parallel, sensor 3 in series + String var1 = "sensor1"; + String var2 = "sensor2"; + String var3 = "sensor3"; + Term s1 = new LiteralTerm<>(var1); + Term s2 = new LiteralTerm<>(var2); + Term s3 = new LiteralTerm<>(var3); + ORTerm or = new ORTerm(); + or.add(s1, s2); + ANDTerm and = new ANDTerm(); + and.add(or, s3); + + SL sl = new SL(and); + + Map failedComponents = new HashMap(); + + // First sensor failure should return proper working system + failedComponents.put(var1, false); + Assertions.assertTrue(sl.isProvidingService(failedComponents)); + + // Second sensor failure should return failed system + failedComponents.put(var2, false); + Assertions.assertFalse(sl.isProvidingService(failedComponents)); + + // Second sensor back to life, system properly working + failedComponents.put(var2, true); + Assertions.assertTrue(sl.isProvidingService(failedComponents)); + + // Sensor 3 failure cannot be mitigated, system fails + failedComponents.put(var3, false); + Assertions.assertFalse(sl.isProvidingService(failedComponents)); + } + + @Test + public void testGetSetBitStreamLength() { + // Sensor 1 & 2 in parallel, sensor 3 in series + String var1 = "sensor1"; + Term s1 = new LiteralTerm<>(var1); + SL sl = new SL(s1); + + // Default 1 + Assertions.assertEquals(sl.getBitStreamLengthStructureFunction(), 1); + + sl.setBitStreamLengthStructureFunction(100); + // Default 1 + Assertions.assertEquals(sl.getBitStreamLengthStructureFunction(), 100); + } + }