com.sri.ai.praise.lang.grounded.common.FunctionTable Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aic-praise Show documentation
Show all versions of aic-praise Show documentation
SRI International's AIC PRAiSE (Probabilistic Reasoning As Symbolic Evaluation) Library (for Java 1.8+)
/*
* Copyright (c) 2015, SRI International
* All rights reserved.
* Licensed under the The BSD 3-Clause License;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://opensource.org/licenses/BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the aic-praise nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sri.ai.praise.lang.grounded.common;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import com.google.common.annotations.Beta;
import com.sri.ai.util.collect.CartesianProductEnumeration;
import com.sri.ai.util.math.MixedRadixNumber;
/**
* Basic representation of a function described by a table of values.
*
* @author oreilly
*
*/
@Beta
public class FunctionTable {
private List varCardinalities = new ArrayList<>();
private List entries;
private MixedRadixNumber entryIndex;
public FunctionTable(List varCardinalities, List entries) {
this.varCardinalities.addAll(varCardinalities);
this.varCardinalities = Collections.unmodifiableList(this.varCardinalities);
this.entries = new ArrayList<>(entries);
int numEntriesExpected = numEntriesFor(varCardinalities);
if (numEntriesExpected != this.entries.size()) {
throw new IllegalArgumentException("#entries "+this.entries.size()+" does not match the expected # of "+numEntriesExpected);
}
this.entryIndex = new MixedRadixNumber(BigInteger.ZERO, this.varCardinalities);
}
public int numberVariables() {
return varCardinalities.size();
}
public int cardinality(int varIdx) {
return varCardinalities.get(varIdx);
}
public List getVariableCardinalities() {
return varCardinalities;
}
public int numberEntries() {
return entries.size();
}
public List getEntries() {
return entries;
}
public Double entryFor(List varValues) {
Double result = null;
int[] radixValues = new int[varValues.size()];
for (int i = 0; i < radixValues.length; i++) {
radixValues[i] = varValues.get(i);
}
result = entries.get(this.entryIndex.getValueFor(radixValues).intValue());
return result;
}
public Double valueFor(Map assignmentMap) {
double result = 0;
// If have all assignments then get the entry straight off as opposed to summing them
if (assignmentMap.size() == varCardinalities.size()) {
result = entryFor(IntStream.range(0, varCardinalities.size()).boxed().map(i -> assignmentMap.get(i)).collect(Collectors.toList()));
}
else {
// More than 1 entry value needs to be summed up
List> possibleValues = new ArrayList<>();
for (int i = 0; i < varCardinalities.size(); i++) {
Integer value = assignmentMap.get(i);
if (value == null) {
possibleValues.add(IntStream.range(0, varCardinalities.get(i)).boxed().collect(Collectors.toList()));
}
else {
possibleValues.add(Arrays.asList(value));
}
}
CartesianProductEnumeration cpe = new CartesianProductEnumeration<>(possibleValues);
while (cpe.hasMoreElements()) {
result += entryFor(cpe.nextElement());
}
}
return result;
}
public static int numEntriesFor(List varCardinalities) {
int result = 0;
if (varCardinalities.size() > 0) {
result = varCardinalities.stream().reduce((card1, card2) -> card1 * card2).get();
}
return result;
}
public static List> cardinalityValues(List varCardinalities) {
List> result = new ArrayList<>();
for (Integer card : varCardinalities) {
result.add(IntStream.range(0, card).boxed().collect(Collectors.toList()));
}
return result;
}
@Override
public boolean equals(Object obj) {
if (obj != null && obj instanceof FunctionTable) {
FunctionTable other = (FunctionTable) obj;
return this.varCardinalities.equals(other.varCardinalities) && this.entries.equals(other.entries);
}
return false;
}
@Override
public int hashCode() {
return this.varCardinalities.hashCode() + this.entries.hashCode();
}
}