/*******************************************************************************
* 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.common;
import static org.junit.Assert.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import br.usp.poli.takiyama.prv.CountingFormula;
import br.usp.poli.takiyama.prv.LogicalVariable;
import br.usp.poli.takiyama.prv.Prv;
import br.usp.poli.takiyama.prv.StdLogicalVariable;
import br.usp.poli.takiyama.prv.StdPrv;
import br.usp.poli.takiyama.prv.Term;
import br.usp.poli.takiyama.utils.Lists;
import br.usp.poli.takiyama.utils.MathUtils;
public class FactorTest {
/**
* Sums out f(X) from factor
* <p>
* <table border="1">
* <tr><th>f(X)</th><th>g(X,Y)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>0.1</td></tr>
* <tr><td>false</td><td>true</td><td>0.2</td></tr>
* <tr><td>true</td><td>false</td><td>0.3</td></tr>
* <tr><td>true</td><td>true</td><td>0.4</td></tr>
* </table>
* </p>
* which results in factor
* <p>
* <table border="1">
* <tr><th>g(X,Y)</th><th>values</th></tr>
* <tr><td>false</td><td>0.4</td></tr>
* <tr><td>true</td><td>0.6</td></tr>
* </table>
* </p>
*/
@Test
public void testSumOutFirstVar() {
Term x = StdLogicalVariable.getInstance("X", "x", 10);
Term y = StdLogicalVariable.getInstance("Y", "x", 10);
Prv f = StdPrv.getBooleanInstance("f", x);
Prv g = StdPrv.getBooleanInstance("g", x, y);
List<Prv> vars = new ArrayList<Prv>(2);
vars.add(f);
vars.add(g);
List<BigDecimal> vals = new ArrayList<BigDecimal>(4);
vals.add(new BigDecimal(0.1));
vals.add(new BigDecimal(0.2));
vals.add(new BigDecimal(0.3));
vals.add(new BigDecimal(0.4));
Factor factor = StdFactor.getInstance("F", vars, vals);
Factor result = factor.sumOut(f);
List<Prv> ansVars = new ArrayList<Prv>(1);
ansVars.add(g);
List<BigDecimal> ansVals = new ArrayList<BigDecimal>(2);
ansVals.add(new BigDecimal(0.1).add(new BigDecimal(0.3), MathUtils.CONTEXT));
ansVals.add(new BigDecimal(0.2).add(new BigDecimal(0.4), MathUtils.CONTEXT));
Factor answer = StdFactor.getInstance("F", ansVars, ansVals);
assertTrue(result.equals(answer));
}
/**
* Sums out g(X,Y) from factor
* <p>
* <table border="1">
* <tr><th>f(X)</th><th>g(X,Y)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>0.1</td></tr>
* <tr><td>false</td><td>true</td><td>0.2</td></tr>
* <tr><td>true</td><td>false</td><td>0.3</td></tr>
* <tr><td>true</td><td>true</td><td>0.4</td></tr>
* </table>
* </p>
* which results in factor
* <p>
* <table border="1">
* <tr><th>f(X)</th><th>values</th></tr>
* <tr><td>false</td><td>0.3</td></tr>
* <tr><td>true</td><td>0.7</td></tr>
* </table>
* </p>
*/
@Test
public void testSumOutSecondVar() {
Term x = StdLogicalVariable.getInstance("X", "x", 10);
Term y = StdLogicalVariable.getInstance("Y", "x", 10);
Prv f = StdPrv.getBooleanInstance("f", x);
Prv g = StdPrv.getBooleanInstance("g", x, y);
List<Prv> vars = new ArrayList<Prv>(2);
vars.add(f);
vars.add(g);
List<BigDecimal> vals = new ArrayList<BigDecimal>(4);
vals.add(new BigDecimal(0.1));
vals.add(new BigDecimal(0.2));
vals.add(new BigDecimal(0.3));
vals.add(new BigDecimal(0.4));
Factor factor = StdFactor.getInstance("F", vars, vals);
Factor result = factor.sumOut(g);
List<Prv> ansVars = new ArrayList<Prv>(1);
ansVars.add(f);
List<BigDecimal> ansVals = new ArrayList<BigDecimal>(2);
ansVals.add(new BigDecimal(0.1).add(new BigDecimal(0.2), MathUtils.CONTEXT));
ansVals.add(new BigDecimal(0.3).add(new BigDecimal(0.4), MathUtils.CONTEXT));
Factor answer = StdFactor.getInstance("F", ansVars, ansVals);
assertTrue(result.equals(answer));
}
/**
* 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 = 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() {
Term a = StdLogicalVariable.getInstance("A", "x", 2);
Term b = StdLogicalVariable.getInstance("B", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
Prv cf = CountingFormula.getInstance((LogicalVariable) a, f);
List<Prv> vars = new ArrayList<Prv>(2);
vars.add(cf);
vars.add(h);
List<BigDecimal> vals = new ArrayList<BigDecimal>(6);
vals.add(new BigDecimal(1));
vals.add(new BigDecimal(10));
vals.add(new BigDecimal(100));
vals.add(new BigDecimal(1000));
vals.add(new BigDecimal(10000));
vals.add(new BigDecimal(100000));
Factor factor = StdFactor.getInstance("F", vars, vals);
Factor result = factor.sumOut(cf);
List<Prv> ansVars = new ArrayList<Prv>(1);
ansVars.add(h);
List<BigDecimal> ansVals = new ArrayList<BigDecimal>(2);
ansVals.add(new BigDecimal(10201));
ansVals.add(new BigDecimal(102010));
Factor answer = StdFactor.getInstance("F", ansVars, ansVals);
assertTrue(result.equals(answer));
}
/**
* 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 = 0, #.true = 10)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 0, #.true = 10)</td><td>true</td><td>1</td></tr>
* <tr><td>(#.false = 1, #.true = 9)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 1, #.true = 9)</td><td>true</td><td>1</td></tr>
* <tr><td>(#.false = 2, #.true = 8)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 2, #.true = 8)</td><td>true</td><td>1</td></tr>
* <tr><td>(#.false = 3, #.true = 7)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 3, #.true = 7)</td><td>true</td><td>1</td></tr>
* <tr><td>(#.false = 4, #.true = 6)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 4, #.true = 6)</td><td>true</td><td>1</td></tr>
* <tr><td>(#.false = 5, #.true = 5)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 5, #.true = 5)</td><td>true</td><td>1</td></tr>
* <tr><td>(#.false = 6, #.true = 4)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 6, #.true = 4)</td><td>true</td><td>1</td></tr>
* <tr><td>(#.false = 7, #.true = 3)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 7, #.true = 3)</td><td>true</td><td>1</td></tr>
* <tr><td>(#.false = 8, #.true = 2)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 8, #.true = 2)</td><td>true</td><td>1</td></tr>
* <tr><td>(#.false = 9, #.true = 1)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 9, #.true = 1)</td><td>true</td><td>1</td></tr>
* <tr><td>(#.false = 10, #.true = 0)</td><td>false</td><td>1</td></tr>
* <tr><td>(#.false = 10, #.true = 0)</td><td>true</td><td>1</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>1024</td></tr>
* <tr><td>true</td><td>1024</td></tr>
* </table>
* </p>
*/
@Test
public void testSumOutBiggerCountingFormula() {
Term a = StdLogicalVariable.getInstance("A", "x", 10);
Term b = StdLogicalVariable.getInstance("B", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
Prv cf = CountingFormula.getInstance((LogicalVariable) a, f);
List<Prv> vars = new ArrayList<Prv>(2);
vars.add(cf);
vars.add(h);
List<BigDecimal> vals = new ArrayList<BigDecimal>(22);
for (int i = 0; i < 22; i++) {
vals.add(new BigDecimal(1));
}
Factor factor = StdFactor.getInstance("F", vars, vals);
Factor result = factor.sumOut(cf);
List<Prv> ansVars = new ArrayList<Prv>(1);
ansVars.add(h);
List<BigDecimal> ansVals = new ArrayList<BigDecimal>(2);
ansVals.add(new BigDecimal(1024));
ansVals.add(new BigDecimal(1024));
Factor answer = StdFactor.getInstance("F", ansVars, ansVals);
assertTrue(result.equals(answer));
}
/**
* Raises factor
* <p>
* <table border="1">
* <tr><th>f(X)</th><th>g(X,Y)</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>4</td></tr>
* <tr><td>true</td><td>true</td><td>0</td></tr>
* </table>
* </p>
* to power 2, which results in factor
* <p>
* <table border="1">
* <tr><th>f(X)</th><th>g(X,Y)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>4</td></tr>
* <tr><td>false</td><td>true</td><td>9</td></tr>
* <tr><td>true</td><td>false</td><td>16</td></tr>
* <tr><td>true</td><td>true</td><td>0</td></tr>
* </table>
* </p>
*/
@Test
public void testPowExponent2() {
Term a = StdLogicalVariable.getInstance("A", "x", 10);
Term b = StdLogicalVariable.getInstance("B", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
List<Prv> vars = new ArrayList<Prv>(2);
vars.add(f);
vars.add(h);
List<BigDecimal> vals = new ArrayList<BigDecimal>(4);
vals.add(new BigDecimal(2));
vals.add(new BigDecimal(3));
vals.add(new BigDecimal(4));
vals.add(new BigDecimal(0));
Factor factor = StdFactor.getInstance("F", vars, vals);
Factor result = factor.pow(2, 1);
List<Prv> ansVars = new ArrayList<Prv>(2);
ansVars.add(f);
ansVars.add(h);
List<BigDecimal> ansVals = new ArrayList<BigDecimal>(4);
ansVals.add(new BigDecimal(4));
ansVals.add(new BigDecimal(9));
ansVals.add(new BigDecimal(16));
ansVals.add(new BigDecimal(0));
Factor answer = StdFactor.getInstance("F", ansVars, ansVals);
assertTrue(result.equals(answer));
}
/**
* Raises factor
* <p>
* <table border="1">
* <tr><th>f(X)</th><th>g(X,Y)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>0</td></tr>
* <tr><td>false</td><td>true</td><td>4</td></tr>
* <tr><td>true</td><td>false</td><td>9</td></tr>
* <tr><td>true</td><td>true</td><td>16</td></tr>
* </table>
* </p>
* to power 1/2 (square root), which results in factor
* <p>
* <table border="1">
* <tr><th>f(X)</th><th>g(X,Y)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>0</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>
*/
@Test
public void testPowSqrt() {
Term a = StdLogicalVariable.getInstance("A", "x", 10);
Term b = StdLogicalVariable.getInstance("B", "x", 3);
Prv f = StdPrv.getBooleanInstance("f", a);
Prv h = StdPrv.getBooleanInstance("h", b);
List<Prv> vars = new ArrayList<Prv>(2);
vars.add(f);
vars.add(h);
List<BigDecimal> vals = new ArrayList<BigDecimal>(4);
vals.add(new BigDecimal(0));
vals.add(new BigDecimal(4));
vals.add(new BigDecimal(9));
vals.add(new BigDecimal(16));
Factor factor = StdFactor.getInstance("F", vars, vals);
Factor result = factor.pow(1, 2);
List<Prv> ansVars = new ArrayList<Prv>(2);
ansVars.add(f);
ansVars.add(h);
List<BigDecimal> ansVals = new ArrayList<BigDecimal>(4);
ansVals.add(new BigDecimal(0));
ansVals.add(new BigDecimal(2));
ansVals.add(new BigDecimal(3));
ansVals.add(new BigDecimal(4));
Factor answer = StdFactor.getInstance("F", ansVars, ansVals);
assertTrue(result.equals(answer));
}
/**
* Multiplies factor
* <p>
* <table border="1">
* <tr><th>f(X)</th><th>values</th></tr>
* <tr><td>false</td><td>0.1</td></tr>
* <tr><td>false</td><td>0.2</td></tr>
* </table>
* </p>
* and factor
* <p>
* <table border="1">
* <tr><th>f(X)</th><th>g(X,Y)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>0.1</td></tr>
* <tr><td>false</td><td>true</td><td>0.2</td></tr>
* <tr><td>true</td><td>false</td><td>0.3</td></tr>
* <tr><td>true</td><td>true</td><td>0.4</td></tr>
* </table>
* </p>
* which results in factor
* <p>
* <table border="1">
* <tr><th>f(X)</th><th>g(X,Y)</th><th>values</th></tr>
* <tr><td>false</td><td>false</td><td>0.01</td></tr>
* <tr><td>false</td><td>true</td><td>0.02</td></tr>
* <tr><td>true</td><td>false</td><td>0.06</td></tr>
* <tr><td>true</td><td>true</td><td>0.08</td></tr>
* </table>
* </p>
*/
@Test
public void testSimpleMultiplication() {
Term x = StdLogicalVariable.getInstance("X", "x", 10);
Term y = StdLogicalVariable.getInstance("Y", "x", 10);
Prv f = StdPrv.getBooleanInstance("f", x);
Prv h = StdPrv.getBooleanInstance("h", x, y);
List<Prv> vars1 = new ArrayList<Prv>(1);
vars1.add(f);
List<BigDecimal> vals1 = new ArrayList<BigDecimal>(2);
vals1.add(new BigDecimal(0.1));
vals1.add(new BigDecimal(0.2));
Factor factor1 = StdFactor.getInstance("F1", vars1, vals1);
List<Prv> vars2 = new ArrayList<Prv>(1);
vars2.add(f);
vars2.add(h);
List<BigDecimal> vals2 = new ArrayList<BigDecimal>(4);
vals2.add(new BigDecimal(0.1));
vals2.add(new BigDecimal(0.2));
vals2.add(new BigDecimal(0.3));
vals2.add(new BigDecimal(0.4));
Factor factor2 = StdFactor.getInstance("F2", vars2, vals2);
Factor result = factor1.multiply(factor2);
List<Prv> ansVars = new ArrayList<Prv>(2);
ansVars.add(f);
ansVars.add(h);
List<BigDecimal> ansVals = new ArrayList<BigDecimal>(4);
ansVals.add(new BigDecimal(0.1).multiply(new BigDecimal(0.1), MathUtils.CONTEXT));
ansVals.add(new BigDecimal(0.1).multiply(new BigDecimal(0.2), MathUtils.CONTEXT));
ansVals.add(new BigDecimal(0.2).multiply(new BigDecimal(0.3), MathUtils.CONTEXT));
ansVals.add(new BigDecimal(0.2).multiply(new BigDecimal(0.4), MathUtils.CONTEXT));
Factor answer = StdFactor.getInstance("F", ansVars, ansVals);
assertTrue(result.equals(answer));
}
/**
* Multiplies a factor by 1. Expected result is the factor itself.
*/
@Test
public void testMultiplicationBy1() {
Factor constant = StdFactor.getInstance();
Prv f = StdPrv.getBooleanInstance("f");
Prv h = StdPrv.getBooleanInstance("h");
List<Prv> vars = Lists.listOf(f, h);
List<BigDecimal> vals = Lists.listOf(
BigDecimal.valueOf(1.0),
BigDecimal.valueOf(2.0),
BigDecimal.valueOf(3.0),
BigDecimal.valueOf(4.0));
Factor factor = StdFactor.getInstance("f", vars, vals);
Factor result = factor.multiply(constant);
Factor expected = factor;
assertEquals(expected, result);
}
}