/*******************************************************************************
* Copyright (C) 2008-2012 Dominik Jain.
*
* This file is part of ProbCog.
*
* ProbCog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProbCog 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProbCog. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package probcog.logic.sat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.Vector;
import java.util.Map.Entry;
import probcog.logic.GroundAtom;
import probcog.logic.PossibleWorld;
import probcog.logic.WorldVariables;
import probcog.logic.WorldVariables.Block;
import probcog.srl.AbstractVariable;
import edu.tum.cs.util.datastruct.Map2Set;
// TODO we could speed some of this up by explicitly keeping track of blocked and unblocked non-evidence vars
/**
* Helper class for handling evidence.
* @author Dominik Jian
*/
public class EvidenceHandler {
protected static boolean verbose = false;
protected HashMap<Integer,Boolean> evidence;
protected HashSet<Block> evidenceBlocks;
protected Map2Set<Block, GroundAtom> blockExclusions;
protected WorldVariables vars;
protected Random rand;
public EvidenceHandler(WorldVariables vars, Iterable<? extends AbstractVariable<?>> db) throws Exception {
this.vars = vars;
this.rand = new Random();
this.evidence = new HashMap<Integer,Boolean>();
evidenceBlocks = new HashSet<Block>();
blockExclusions = new Map2Set<Block,GroundAtom>();
for(AbstractVariable<?> var : db) {
String strGndAtom = var.getPredicate();
GroundAtom gndAtom = vars.get(strGndAtom);
if(gndAtom == null) {
if(var.pertainsToEvidenceFunction()) // pure evidence functions may be missing from the model altogether
continue;
else
throw new Exception("Evidence ground atom '" + strGndAtom + "' not in set of world variables.");
}
if(!var.isBoolean()) { // if the variable isn't boolean, it is mapped to a block, which we set in its entirety
Block block = vars.getBlock(gndAtom.index);
if(block == null)
throw new Exception(String.format("There is no variable block to which the non-boolean variable assignment '%s' can be mapped.", var.toString()));
for(GroundAtom ga : block)
this.evidence.put(ga.index, var.value.equals(ga.args[ga.args.length-1]));
evidenceBlocks.add(block);
}
else {
boolean truthValue = var.isTrue();
this.evidence.put(gndAtom.index, truthValue);
Block block = vars.getBlock(gndAtom.index);
if(block != null) {
if(truthValue == true) {
for(GroundAtom ga : block)
this.evidence.put(ga.index, ga.index == gndAtom.index);
evidenceBlocks.add(block);
}
else {
blockExclusions.add(block, gndAtom);
}
}
}
}
}
public void setEvidenceInState(PossibleWorld state) {
for(Entry<Integer, Boolean> e : this.evidence.entrySet())
state.set(e.getKey(), e.getValue());
}
/**
* sets a random state for the non-evidence atoms
* @param state
*/
public void setRandomState(PossibleWorld state) throws Exception {
HashSet<Block> handledBlocks = new HashSet<Block>();
for(int i = 0; i < vars.size(); i++) {
//System.out.println(" setting " + vars.get(i));
Block block = vars.getBlock(i);
if(block != null) {
if(this.evidenceBlocks.contains(block) || handledBlocks.contains(block))
continue;
// if we do not need to handle block exclusions, we just set any ground atom in the block to true and the others to false
Set<GroundAtom> excl = blockExclusions.get(block);
if(excl == null) {
int j = rand.nextInt(block.size());
for(int k = 0; k < block.size(); k++) {
boolean value = k == j;
state.set(block.get(k), value);
}
}
// if we do need to handle exclusions, collect a set of possible true ones and set one of them to true
else {
Vector<GroundAtom> possibleTrueOnes = new Vector<GroundAtom>();
for(GroundAtom gndAtom : block) {
if(!excl.contains(gndAtom))
possibleTrueOnes.add(gndAtom);
}
if(possibleTrueOnes.isEmpty())
throw new Exception("Invalid Evidence: The block of variables " + block + " contains only false atoms");
GroundAtom trueOne = possibleTrueOnes.get(rand.nextInt(possibleTrueOnes.size()));
for(GroundAtom gndAtom : block)
state.set(gndAtom, trueOne == gndAtom);
}
handledBlocks.add(block);
}
else {
if(!this.evidence.containsKey(i))
state.set(i, rand.nextBoolean());
}
}
}
public HashMap<Integer, Boolean> getEvidence() {
return evidence;
}
}