/*******************************************************************************
* Copyright 2014 Felipe Takiyama
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package br.usp.poli.takiyama.cfove;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import br.usp.poli.takiyama.cfove.StdParfactor.StdParfactorBuilder;
import br.usp.poli.takiyama.common.Constraint;
import br.usp.poli.takiyama.common.FactorTest;
import br.usp.poli.takiyama.common.InequalityConstraint;
import br.usp.poli.takiyama.common.Parfactor;
import br.usp.poli.takiyama.common.SplitResult;
import br.usp.poli.takiyama.prv.Binding;
import br.usp.poli.takiyama.prv.Constant;
import br.usp.poli.takiyama.prv.CountingFormula;
import br.usp.poli.takiyama.prv.LogicalVariable;
import br.usp.poli.takiyama.prv.Operator;
import br.usp.poli.takiyama.prv.Prv;
import br.usp.poli.takiyama.prv.RangeElement;
import br.usp.poli.takiyama.prv.StdLogicalVariable;
import br.usp.poli.takiyama.prv.StdPrv;
import br.usp.poli.takiyama.prv.Substitution;
import br.usp.poli.takiyama.prv.Term;
import br.usp.poli.takiyama.utils.MathUtils;
import br.usp.poli.takiyama.utils.TestUtils;
/**
* Unit tests for {@link StdParfactor}s.
*
* @author Felipe Takiyama
*/
public class StdParfactorTest {
/**
* Example 2.15 from [Kisynski,2010].
* <p>
* Splits parfactor <C,V,F> on substitution {B/x1}, where C = {A ≠ B},
* V = {f(A, B), h(B)} and F is given by
* </p>
* <p>
* <table border="1">
* <tr><th>f(A,B)</th><th>h(B)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>0.2</td></tr>
* <tr><td>false</td><td>true</td><td>0.3</td></tr>
* <tr><td>true</td><td>false</td><td>0.5</td></tr>
* <tr><td>true</td><td>true</td><td>0.7</td></tr>
* </table>
* </p>
* <p>
* The result of this operation is parfactor g[B/x1], where C[B/x1] =
* {A ≠ x1}, V[B/x1] = {f(A, x1), h(x1)} and F[B/x1] has the same values
* as F. The residue is parfactor g', where C' = {A ≠ B. B ≠ x1},
* V' = V and F' = F.
* </p>
*/
@Test
public void testSplit() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 10);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", 10);
Constant x1 = Constant.getInstance("x1");
Prv f = StdPrv.getBooleanInstance("f", a, b);
Prv h = StdPrv.getBooleanInstance("h", b);
Prv f1 = StdPrv.getBooleanInstance("f", a, x1);
Prv h1 = StdPrv.getBooleanInstance("h", x1);
Constraint ab = InequalityConstraint.getInstance(a, b);
Constraint a0 = InequalityConstraint.getInstance(a, x1);
Constraint b0 = InequalityConstraint.getInstance(b, x1);
double [] vals = {0.2, 0.3, 0.5, 0.7};
Parfactor input = new StdParfactorBuilder().constraints(ab)
.variables(f, h).values(vals).build();
Binding binding = Binding.getInstance(b, x1);
Substitution sub = Substitution.getInstance(binding);
SplitResult output = input.splitOn(sub);
Parfactor result = new StdParfactorBuilder().constraints(a0)
.variables(f1, h1).values(vals).build();
Parfactor residue = new StdParfactorBuilder().constraints(ab, b0)
.variables(f, h).values(vals).build();
SplitResult answer = SplitResult.getInstance(result, residue);
assertEquals(output, answer);
}
/**
* Example 2.14 from Kisysnki (2010)
* <p>
* Multiplies parfactor g1 = ⟨ {A≠B}, {f(A,B),h(B)}, F1 ⟩
* with parfactor g2 = ⟨ ∅, {e(C),h(B)}, F2 ⟩, where
* </p>
* <p>
* F1
* <table border="1">
* <tr><th>f(A,B)</th><th>h(B)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>α1</td></tr>
* <tr><td>false</td><td>true</td><td>α2</td></tr>
* <tr><td>true</td><td>false</td><td>α3</td></tr>
* <tr><td>true</td><td>true</td><td>α4</td></tr>
* </table>
* </p>
* <p>
* F2
* <table border="1">
* <tr><th>e(C)</th><th>h(B)</th><th>values</th></tr>
* <tr><td>green</td><td>false</td><td>β1</td></tr>
* <tr><td>green</td><td>true</td><td>β2</td></tr>
* <tr><td>orange</td><td>false</td><td>β3</td></tr>
* <tr><td>orange</td><td>true</td><td>β4</td></tr>
* <tr><td>red</td><td>false</td><td>β5</td></tr>
* <tr><td>red</td><td>true</td><td>β6</td></tr>
* </table>
* </p>
* <p>
* D(A) = D(B) = {x1,...,xn} and D(C) = {y1,...,ym}. The result of this
* operation is parfactor g = ⟨ {A≠B}, {f(A,B),h(B),e(C)},
* F ⟩, where
* <p>
* F
* <table border="1">
* <tr><th>f(A,B)</th><th>h(B)</th><th>e(C)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>green</td> <td>α1<sup>1/m</sup>β1<sup>1/(n-1)</sup></td></tr>
* <tr><td>false</td><td>false</td><td>orange</td> <td>α1<sup>1/m</sup>β3<sup>1/(n-1)</sup></td></tr>
* <tr><td>false</td><td>false</td><td>red</td> <td>α1<sup>1/m</sup>β5<sup>1/(n-1)</sup></td></tr>
* <tr><td>false</td><td>true</td><td>green</td> <td>α2<sup>1/m</sup>β2<sup>1/(n-1)</sup></td></tr>
* <tr><td>false</td><td>true</td><td>orange</td> <td>α2<sup>1/m</sup>β4<sup>1/(n-1)</sup></td></tr>
* <tr><td>false</td><td>true</td><td>red</td> <td>α2<sup>1/m</sup>β6<sup>1/(n-1)</sup></td></tr>
* <tr><td>true</td><td>false</td><td>green</td> <td>α3<sup>1/m</sup>β1<sup>1/(n-1)</sup></td></tr>
* <tr><td>true</td><td>false</td><td>orange</td> <td>α3<sup>1/m</sup>β3<sup>1/(n-1)</sup></td></tr>
* <tr><td>true</td><td>false</td><td>red</td> <td>α3<sup>1/m</sup>β5<sup>1/(n-1)</sup></td></tr>
* <tr><td>true</td><td>true</td><td>green</td> <td>α4<sup>1/m</sup>β2<sup>1/(n-1)</sup></td></tr>
* <tr><td>true</td><td>true</td><td>orange</td> <td>α4<sup>1/m</sup>β4<sup>1/(n-1)</sup></td></tr>
* <tr><td>true</td><td>true</td><td>red</td> <td>α4<sup>1/m</sup>β6<sup>1/(n-1)</sup></td></tr>
* </table>
* </p>
*/
@Test
public void testMultiplication() {
// Population size for A and B
int n = 5;
// Population size for C
int m = 6;
// Logical variables A, B and C
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", n);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", n);
LogicalVariable c = StdLogicalVariable.getInstance("C", "y", m);
// PRVs f(A,B) and h(B)
Prv f = StdPrv.getBooleanInstance("f", a, b);
Prv h = StdPrv.getBooleanInstance("h", b);
// PRV e(C), where range(e) = {green, orange, red}
List<RangeElement> eRange = new ArrayList<RangeElement>(
Arrays.asList(Color.values()));
List<Term> eParam = new ArrayList<Term>(1);
eParam.add(c);
Prv e = StdPrv.getInstance("e", eRange, eParam);
// Constraint A != B
Constraint ab = InequalityConstraint.getInstance(a, b);
// Parfactor g1
double [] g1vals = {1.0, 2.0, 3.0, 4.0};
Parfactor g1 = new StdParfactorBuilder().constraints(ab)
.variables(f, h).values(g1vals).build();
// Parfactor g2
double [] g2vals = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
Parfactor g2 = new StdParfactorBuilder().variables(e, h)
.values(g2vals).build();
Parfactor product = g1.multiply(g2);
// Answer
List<BigDecimal> ansVals = new ArrayList<BigDecimal>(12);
for (int i = 0; i < g1vals.length; i++) {
BigDecimal alpha = BigDecimal.valueOf(g1vals[i]);
BigDecimal alphaM = MathUtils.pow(alpha, 1, m);
for (int j = i % 2; j < g2vals.length; j = j + 2) {
BigDecimal beta = BigDecimal.valueOf(g2vals[j]);
BigDecimal betaN = MathUtils.pow(beta, 1, n - 1);
ansVals.add(alphaM.multiply(betaN, MathUtils.CONTEXT));
}
}
Parfactor answer = new StdParfactorBuilder().constraints(ab)
.variables(f, h, e).values(ansVals).build();
assertTrue(product.equals(answer));
}
// public void testMultiplicationWithCountingFormula() {
// int n = 5;
//
// // Logical variables A, B and C
// LogicalVariable a = StdLogicalVariable.getInstance("A", "x", n);
// LogicalVariable b = StdLogicalVariable.getInstance("B", "x", n);
//
// Constant x1 = Constant.getInstance("x1");
//
// Constraint a_x1 = InequalityConstraint.getInstance(a, x1);
//
// // PRVs f(A,B) #.B [f(A,B)]
// Prv f = StdPrv.getBooleanInstance("f", a, b);
// Prv cf = CountingFormula.getInstance(b, f);
//
// List<BigDecimal> f1 = TestUtils.toBigDecimalList(2, 4, 6, 8, 10, 12);
// List<BigDecimal> f2 = TestUtils.toBigDecimalList(3, 5);
//
// Parfactor g1 = new StdParfactorBuilder().constraints(a_x1)
// .variables(cf).values(f1).build();
// Parfactor g2 = new StdParfactorBuilder().constraints(a_x1)
// .variables(f).values(f2).build();
//
// Parfactor product = g1.multiply(g2);
// Parfactor expected = new StdParfactorBuilder().constraints(a_x1)
// .variables(cf).values(f3).build();
//
// assertEquals(expected, product);
// }
// TODO improve this test
@Test
public void testMultiplicationConditions() {
int n = 2;
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", n);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", n);
LogicalVariable c = StdLogicalVariable.getInstance("C", "x", n);
Constant x1 = Constant.getInstance("x1");
Prv f = StdPrv.getBooleanInstance("f", a, b);
Prv f_a_x1 = StdPrv.getBooleanInstance("f", a, x1);
Prv h = StdPrv.getBooleanInstance("h", c);
Prv cf1 = CountingFormula.getInstance(a, f);
Prv cf2 = CountingFormula.getInstance(a, f_a_x1);
List<BigDecimal> f1 = TestUtils.toBigDecimalList(2, 4, 6);
List<BigDecimal> f2 = TestUtils.toBigDecimalList(3, 5);
List<BigDecimal> f3 = TestUtils.toBigDecimalList(3, 5, 7, 11);
Parfactor g1 = new StdParfactorBuilder().variables(cf1).values(f1).build();
Parfactor g2 = new StdParfactorBuilder().variables(f).values(f2).build();
Parfactor g3 = new StdParfactorBuilder().variables(cf2).values(f1).build();
Parfactor g4 = new StdParfactorBuilder().variables(f_a_x1).values(f2).build();
Parfactor g5 = new StdParfactorBuilder().variables(f, h).values(f3).build();
Parfactor g6 = new StdParfactorBuilder().variables(f).values(f2).build();
assertFalse(g1.isMultipliable(g2) || g3.isMultipliable(g4)
|| !g5.isMultipliable(g6) || g5.isMultipliable(g5));
}
/**
* Range for PRV e(C), specified above.
* @see testMultiplication (broken link)
*/
private enum Color implements RangeElement {
GREEN, ORANGE, RED;
/**
* Throws {@link UnsupportedOperationException}.
*/
public RangeElement combine(RangeElement e) {
throw new UnsupportedOperationException("Not implemented");
}
/**
* Throws {@link UnsupportedOperationException}.
*/
@Override
public RangeElement apply(Operator<? extends RangeElement> op) {
throw new UnsupportedOperationException("Not implemented");
}
}
/**
* Sums out #.A[f(A)] from factor
* <p>
* <table border="1">
* <tr><th>#.A[f(A)]</th><th>h(B)</th><th>values</th></tr>
* <tr><td>(#.false = 1, #.true = 0)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 1, #.true = 0)</td><td>true</td><td>10</td></tr>
* <tr><td>(#.false = 0, #.true = 1)</td><td>false</td><td>100</td></tr>
* <tr><td>(#.false = 0, #.true = 1)</td><td>true</td><td>1000</td></tr>
* </table>
* </p>
* which results in factor
* <p>
* <table border="1">
* <tr><th>h(B)</th><th>values</th></tr>
* <tr><td>false</td><td>101</td></tr>
* <tr><td>true</td><td>1010</td></tr>
* </table>
* </p>
*/
@Test
public void testSumOutCountingFormulaWithCardinality1() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 1);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
Prv cf = CountingFormula.getInstance(a, f);
double [] vals = {1.0, 10.0, 100.0, 1000.0};
Parfactor input = new StdParfactorBuilder().variables(cf, h)
.values(vals).build();
Parfactor result = input.sumOut(cf);
double [] ansVals = {101.0, 1010.0};
Parfactor answer = new StdParfactorBuilder().variables(h)
.values(ansVals).build();
assertTrue(result.equals(answer));
}
/**
* @see FactorTest#testSumOutCountingFormula()
*/
@Test
public void testSumOutCountingFormulaWithCardinality2() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 2);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
Prv cf = CountingFormula.getInstance(a, f);
double [] vals = {1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0};
Parfactor input = new StdParfactorBuilder().variables(cf, h)
.values(vals).build();
Parfactor result = input.sumOut(cf);
double [] ansVals = {10201.0, 102010.0};
Parfactor answer = new StdParfactorBuilder().variables(h)
.values(ansVals).build();
assertTrue(result.equals(answer));
}
/**
* @see FactorTest#testSumOutBiggerCountingFormula()
*/
@Test
public void testSumOutCountingFormulaWithCardinality10() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 10);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
Prv cf = CountingFormula.getInstance(a, f);
double [] vals = new double[22];
Arrays.fill(vals, 1.0);
Parfactor input = new StdParfactorBuilder().variables(cf, h)
.values(vals).build();
Parfactor result = input.sumOut(cf);
double [] ansVals = {1024.0, 1024.0};
Parfactor answer = new StdParfactorBuilder().variables(h)
.values(ansVals).build();
assertTrue(result.equals(answer));
}
/**
* Example 2.13 from Kisysnki (2010) [adapted]. Sums out
* #.A:{A≠B}[f(A)] from factor
* <p>
* <table border="1">
* <tr><th>#.A:{A≠B}[f(A)]</th><th>h(B)</th><th>values</th></tr>
* <tr><td>(#.false = 0, #.true = 2)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 0, #.true = 2)</td><td>true</td><td>10</td></tr>
* <tr><td>(#.false = 1, #.true = 1)</td><td>false</td><td>100</td></tr>
* <tr><td>(#.false = 1, #.true = 1)</td><td>true</td><td>1000</td></tr>
* <tr><td>(#.false = 2, #.true = 0)</td><td>false</td><td>10000</td></tr>
* <tr><td>(#.false = 2, #.true = 0)</td><td>true</td><td>100000</td></tr>
* </table>
* </p>
* which results in factor
* <p>
* <table border="1">
* <tr><th>h(B)</th><th>values</th></tr>
* <tr><td>false</td><td>10201</td></tr>
* <tr><td>true</td><td>102010</td></tr>
* </table>
* </p>
*/
@Test
public void testSumOutCountingFormula() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 3);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
Constraint ab = InequalityConstraint.getInstance(a, b);
Prv cf = CountingFormula.getInstance(a, f, ab);
double [] vals = {1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0};
Parfactor input = new StdParfactorBuilder().variables(cf, h)
.values(vals).build();
Parfactor result = input.sumOut(cf);
double [] ansVals = {10201.0, 102010.0};
Parfactor answer = new StdParfactorBuilder().variables(h)
.values(ansVals).build();
assertTrue(result.equals(answer));
}
/**
* Example 2.16 from Kisysnki (2010) [adapted]. Expands
* #.A:{A≠x1}[f(A)] from parfactor
* g = ⟨ ∅, {#.A:{A≠x1}[f(A)],h(B)}, F1 ⟩
* on constant x2. We use D(A) = {x1, x2, x3}. Factor F1 is given by
* <p>
* <table border="1">
* <tr><th>#.A:{A≠x1}[f(A)]</th><th>h(B)</th><th>values</th></tr>
* <tr><td>(#.false = 2, #.true = 0)</td><td>false</td><td>0.2</td></tr>
* <tr><td>(#.false = 2, #.true = 0)</td><td>true</td><td>0.3</td></tr>
* <tr><td>(#.false = 1, #.true = 1)</td><td>false</td><td>0.5</td></tr>
* <tr><td>(#.false = 1, #.true = 1)</td><td>true</td><td>0.7</td></tr>
* <tr><td>(#.false = 0, #.true = 2)</td><td>false</td><td>0.11</td></tr>
* <tr><td>(#.false = 0, #.true = 2)</td><td>true</td><td>0.13</td></tr>
* </table>
* </p>
* <p>
* The result is parfactor
* g = ⟨ ∅, {#.A:{A≠x1', A≠x2}[f(A)],h(B)}, F2 ⟩,
* where F2 is
* </p>
* <p>
* <table border="1">
* <tr><th>#.A:{A≠x1, A≠x2}[f(A)]</th><th>f(x2)</th><th>h(B)</th><th>values</th></tr>
* <tr><td>(#.false = 1, #.true = 0)</td><td>false</td><td>false</td><td>0.2</td></tr>
* <tr><td>(#.false = 1, #.true = 0)</td><td>false</td><td>true</td><td>0.3</td></tr>
* <tr><td>(#.false = 1, #.true = 0)</td><td>true</td><td>false</td><td>0.5</td></tr>
* <tr><td>(#.false = 1, #.true = 0)</td><td>true</td><td>true</td><td>0.7</td></tr>
* <tr><td>(#.false = 0, #.true = 1)</td><td>false</td><td>false</td><td>0.5</td></tr>
* <tr><td>(#.false = 0, #.true = 1)</td><td>false</td><td>true</td><td>0.7</td></tr>
* <tr><td>(#.false = 0, #.true = 1)</td><td>true</td><td>false</td><td>0.11</td></tr>
* <tr><td>(#.false = 0, #.true = 1)</td><td>true</td><td>true</td><td>0.13</td></tr>
* </table>
* </p>
* <p>
* The result can also be written as
* </p>
* <p>
* <table border="1">
* <tr><th>f(x3)</th><th>f(x2)</th><th>h(B)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>false</td><td>0.2</td></tr>
* <tr><td>false</td><td>false</td><td>true</td><td>0.3</td></tr>
* <tr><td>false</td><td>true</td><td>false</td><td>0.5</td></tr>
* <tr><td>false</td><td>true</td><td>true</td><td>0.7</td></tr>
* <tr><td>true</td><td>false</td><td>false</td><td>0.5</td></tr>
* <tr><td>true</td><td>false</td><td>true</td><td>0.7</td></tr>
* <tr><td>true</td><td>true</td><td>false</td><td>0.11</td></tr>
* <tr><td>true</td><td>true</td><td>true</td><td>0.13</td></tr>
* </table>
* </p>
*/
@Test
public void testExpansion() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 3);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", 3);
Constant x1 = Constant.getInstance("x1");
Constant x2 = Constant.getInstance("x2");
Constant x3 = Constant.getInstance("x3");
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
Prv f_x2 = StdPrv.getBooleanInstance("f", x2);
Prv f_x3 = StdPrv.getBooleanInstance("f", x3);
Constraint a_x1 = InequalityConstraint.getInstance(a, x1);
Prv cf = CountingFormula.getInstance(a, f, a_x1);
Parfactor input = new StdParfactorBuilder().variables(cf, h)
.values(0.2, 0.3, 0.5, 0.7, 0.11, 0.13).build();
Parfactor result = input.expand(cf, x2);
Parfactor answer = new StdParfactorBuilder().variables(f_x3, f_x2, h)
.values(0.2, 0.3, 0.5, 0.7, 0.5, 0.7, 0.11, 0.13).build();
assertTrue(result.equals(answer));
}
/**
* Counts PRV f on parfactor g = ⟨ ∅, {f(A)}, F1 ⟩
* where
* <p>
* F1
* <table border="1">
* <tr><th>f(A)</th><th>values</th></tr>
* <tr><td>false</td><td>2</td></tr>
* <tr><td>true</td><td>3</td></tr>
* </table>
* </p>
* <p>
* D(A) = {x1,x2,x3}. The result of this
* operation is parfactor g' = ⟨ ∅, {#.A[f(A)]}, F2 ⟩,
* where
* <p>
* F2
* <table border="1">
* <tr><th>#.A[f(A)]</th><th>values</th></tr>
* <tr><td>(#.false = 3, #.true = 0)</td><td>8</td></tr>
* <tr><td>(#.false = 2, #.true = 1)</td><td>12</td></tr>
* <tr><td>(#.false = 1, #.true = 2)</td><td>18</td></tr>
* <tr><td>(#.false = 0, #.true = 3)</td><td>27</td></tr>
* </table>
* </p>
*/
@Test
public void testCountingWithoutConstraints() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv cf = CountingFormula.getInstance(a, f);
Parfactor input = new StdParfactorBuilder().variables(f)
.values(2, 3).build();
Parfactor result = input.count(a);
Parfactor answer = new StdParfactorBuilder().variables(cf)
.values(8, 12, 18, 27).build();
assertTrue(result.equals(answer));
}
/**
* Tests exception throwing for counting.
* Tries to count a logical variable that does not exist in the parfactor.
*/
@Test(expected=IllegalArgumentException.class)
public void testCoutingException() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 3);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Parfactor input = new StdParfactorBuilder().variables(f)
.values(2, 3).build();
input.count(b);
}
/**
* Counts logical variable A on parfactor
* g = ⟨ {A≠x1}, {f(A)}, F1 ⟩
* where
* <p>
* F1
* <table border="1">
* <tr><th>f(A)</th><th>values</th></tr>
* <tr><td>false</td><td>2</td></tr>
* <tr><td>true</td><td>3</td></tr>
* </table>
* </p>
* <p>
* D(A) = {x1,x2,x3}. The result of this
* operation is parfactor g' = ⟨ ∅, {#.A[f(A)]}, F2 ⟩,
* where
* <p>
* F2
* <table border="1">
* <tr><th>#.A[f(A)]</th><th>values</th></tr>
* <tr><td>(#.false = 2, #.true = 1)</td><td>4</td></tr>
* <tr><td>(#.false = 1, #.true = 2)</td><td>6</td></tr>
* <tr><td>(#.false = 0, #.true = 3)</td><td>9</td></tr>
* </table>
* </p>
*/
@Test
public void testCountingWithConstraints() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 3);
Constant x1 = Constant.getInstance("x1");
Constraint a_x1 = InequalityConstraint.getInstance(a, x1);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv cf = CountingFormula.getInstance(a, f, a_x1);
Parfactor input = new StdParfactorBuilder().constraints(a_x1)
.variables(f).values(2, 3).build();
Parfactor result = input.count(a);
Parfactor answer = new StdParfactorBuilder().variables(cf)
.values(4, 6, 9).build();
assertTrue(result.equals(answer));
}
/**
* Counts logical variable A on parfactor
* g = ⟨ ∅, {f(A), h(B)}, F1 ⟩
* where
* <p>
* F1
* <table border="1">
* <tr><th>f(A)</th><th>h(B)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>2</td></tr>
* <tr><td>false</td><td>true</td><td>3</td></tr>
* <tr><td>true</td><td>false</td><td>5</td></tr>
* <tr><td>true</td><td>true</td><td>7</td></tr>
* </table>
* </p>
* <p>
* D(A) = {x1,x2,x3}. The result of this
* operation is parfactor g' = ⟨ ∅, {#.A[f(A)],h(B)}, F2 ⟩,
* where
* <p>
* F2
* <table border="1">
* <tr><th>#.A[f(A)]</th><th>h(B)</th><th>values</th></tr>
* <tr><td>(#.false = 3, #.true = 0)</td><td>false</td><td>8</td></tr>
* <tr><td>(#.false = 3, #.true = 0)</td><td>true</td><td>27</td></tr>
* <tr><td>(#.false = 2, #.true = 1)</td><td>false</td><td>20</td></tr>
* <tr><td>(#.false = 2, #.true = 1)</td><td>true</td><td>63</td></tr>
* <tr><td>(#.false = 1, #.true = 2)</td><td>false</td><td>50</td></tr>
* <tr><td>(#.false = 1, #.true = 2)</td><td>true</td><td>147</td></tr>
* <tr><td>(#.false = 0, #.true = 3)</td><td>false</td><td>125</td></tr>
* <tr><td>(#.false = 0, #.true = 3)</td><td>true</td><td>343</td></tr>
* </table>
* </p>
*/
@Test
public void testCountingrWithoutConstraintsAndTwoVariables() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 3);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
Prv cf = CountingFormula.getInstance(a, f);
Parfactor input = new StdParfactorBuilder().variables(f, h)
.values(2, 3, 5, 7).build();
Parfactor result = input.count(a);
Parfactor answer = new StdParfactorBuilder().variables(cf, h)
.values(8, 27, 20, 63, 50, 147, 125, 343).build();
assertTrue(result.equals(answer));
}
/**
* Counts logical variable A on parfactor
* g = ⟨ {A≠B}, {f(A), h(B)}, F1 ⟩
* where
* <p>
* F1
* <table border="1">
* <tr><th>f(A)</th><th>h(B)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>2</td></tr>
* <tr><td>false</td><td>true</td><td>3</td></tr>
* <tr><td>true</td><td>false</td><td>5</td></tr>
* <tr><td>true</td><td>true</td><td>7</td></tr>
* </table>
* </p>
* <p>
* D(A) = {x1,x2,x3}. The result of this
* operation is parfactor
* g' = ⟨ ∅, {#.A:{A≠B}[f(A)],h(B)}, F2 ⟩,
* where
* <p>
* F2
* <table border="1">
* <tr><th>#.A:{A≠B}[f(A)]</th><th>h(B)</th><th>values</th></tr>
* <tr><td>(#.false = 2, #.true = 0)</td><td>false</td><td>4</td></tr>
* <tr><td>(#.false = 2, #.true = 0)</td><td>true</td><td>9</td></tr>
* <tr><td>(#.false = 1, #.true = 1)</td><td>false</td><td>10</td></tr>
* <tr><td>(#.false = 1, #.true = 1)</td><td>true</td><td>21</td></tr>
* <tr><td>(#.false = 0, #.true = 2)</td><td>false</td><td>25</td></tr>
* <tr><td>(#.false = 0, #.true = 2)</td><td>true</td><td>49</td></tr>
* </table>
* </p>
*/
@Test
public void testCount() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 3);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", 3);
Constraint ab = InequalityConstraint.getInstance(a, b);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
Prv cf = CountingFormula.getInstance(a, f, ab);
Parfactor input = new StdParfactorBuilder().constraints(ab)
.variables(f, h).values(2, 3, 5, 7).build();
Parfactor result = input.count(a);
double [] vals = {4.0, 9.0, 10.0, 21.0, 25.0, 49.0};
Parfactor answer = new StdParfactorBuilder().variables(cf, h)
.values(vals).build();
assertTrue(result.equals(answer));
}
/**
* Simplifies g = ⟨ C, V, F ⟩, where C = {A≠x1, A≠x2,
* A≠x3, A≠B, A≠C, B≠x1, B≠x3, B≠C}, V = {f(A,B)} and
* D(A) = D(B) = D(C) = {x1, x2, x3, x4}.
* <p>
* Result is g' = ⟨ C', V', F ⟩, where C' = {C≠x2, C≠x4}
* and V' = {f(x4,x2)}.
* </p>
*/
@Test
public void testLogicalVariableSimplification() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 4);
LogicalVariable b = StdLogicalVariable.getInstance("B", "x", 4);
LogicalVariable c = StdLogicalVariable.getInstance("C", "x", 4);
Constant x1 = Constant.getInstance("x1");
Constant x2 = Constant.getInstance("x2");
Constant x3 = Constant.getInstance("x3");
Constant x4 = Constant.getInstance("x4");
Prv f = StdPrv.getBooleanInstance("f", a, b);
Prv f_x4_x2= StdPrv.getBooleanInstance("f", x4, x2);
Constraint a_x1 = InequalityConstraint.getInstance(a, x1);
Constraint a_x2 = InequalityConstraint.getInstance(a, x2);
Constraint a_x3 = InequalityConstraint.getInstance(a, x3);
Constraint a_b = InequalityConstraint.getInstance(a, b);
Constraint a_c = InequalityConstraint.getInstance(a, c);
Constraint b_x1 = InequalityConstraint.getInstance(b, x1);
Constraint b_x3 = InequalityConstraint.getInstance(b, x3);
Constraint b_c = InequalityConstraint.getInstance(b, c);
Constraint c_x2 = InequalityConstraint.getInstance(c, x2);
Constraint c_x4 = InequalityConstraint.getInstance(c, x4);
Parfactor input = new StdParfactorBuilder()
.constraints(a_x1, a_x2, a_x3, a_b, a_c, b_x1, b_x3, b_c)
.variables(f).values(0.2, 0.3).build();
Parfactor result = input.simplifyLogicalVariables();
Parfactor expected = new StdParfactorBuilder().constraints(c_x2, c_x4).variables(f_x4_x2).values(0.2, 0.3).build();
assertEquals(expected, result);
}
@Test
public void testLogicalVariableSimplificationWithoutConstraints() {
LogicalVariable a = StdLogicalVariable.getInstance("A", "x", 1);
Constant x1 = Constant.getInstance("x1");
Prv f = StdPrv.getBooleanInstance("f", a);
Prv f_x1 = StdPrv.getBooleanInstance("f", x1);
Parfactor input = new StdParfactorBuilder().variables(f).values(0, 1).build();
Parfactor result = input.simplifyLogicalVariables();
Parfactor expected = new StdParfactorBuilder().variables(f_x1).values(0, 1).build();
assertEquals(expected, result);
}
}