/**
*
*/
package xhail.core.entities;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections4.iterators.ArrayIterator;
import xhail.core.Buildable;
import xhail.core.Config;
import xhail.core.parser.Parser;
import xhail.core.statements.Display;
import xhail.core.statements.Example;
import xhail.core.statements.ModeB;
import xhail.core.statements.ModeH;
import xhail.core.terms.Atom;
import xhail.core.terms.Clause;
import xhail.core.terms.Literal;
import xhail.core.terms.Number;
import xhail.core.terms.Variable;
/**
* @author stefano
*
*/
public class Hypothesis implements Iterable<Atom> {
public static class Builder implements Buildable<Hypothesis> {
private Set<Literal> covered = new HashSet<>();
private Set<Atom> facts = new HashSet<>();
private Grounding grounding;
private Set<Atom> literals = new HashSet<>();
private Set<Atom> model = new HashSet<>();
private Set<Literal> uncovered = new HashSet<>();
public Builder(Grounding grounding) {
if (null == grounding)
throw new IllegalArgumentException("Illegal 'grounding' argument in Hypothesis.Builder(Grounding): " + grounding);
this.grounding = grounding;
}
public Builder addAtom(Atom atom) {
if (null == atom)
throw new IllegalArgumentException("Illegal 'atom' argument in Hypothesis.Builder.addAtom(Atom): " + atom);
if (atom.getIdentifier().equals("use_clause_literal") && 2 == atom.getArity()) {
literals.add(atom);
} else {
if (grounding.getConfig().isFull() && grounding.hasDisplays() && grounding.lookup(atom))
model.add(atom);
facts.add(atom);
}
return this;
}
public Builder addAtoms(Collection<Atom> atoms) {
if (null == atoms)
throw new IllegalArgumentException("Illegal 'indAtoms' argument in Hypothesis.Builder.addAtoms(Collection<Atom>): " + atoms);
for (Atom atom : atoms)
addAtom(atom);
return this;
}
@Override
public Hypothesis build() {
covered.clear();
uncovered.clear();
for (Example example : grounding.getExamples()) {
Atom atom = example.getAtom();
if (example.isNegated() != facts.contains(atom))
covered.add(new Literal.Builder(atom).setNegated(example.isNegated()).build());
else
uncovered.add(new Literal.Builder(atom).setNegated(example.isNegated()).build());
}
return new Hypothesis(this);
}
public Builder clear() {
this.model.clear();
this.covered.clear();
this.literals.clear();
return this;
}
public Builder parse(Collection<String> answer) {
if (null == answer)
throw new IllegalArgumentException("Illegal 'answer' argument in Hypothesis.Builder.parse(Collection<String>): " + answer);
for (String atom : answer)
addAtom(Parser.parseToken(atom));
return this;
}
public Builder removeAtom(Atom atom) {
if (null == atom)
throw new IllegalArgumentException("Illegal 'atom' argument in Hypothesis.Builder.removeAtom(Atom): " + atom);
if (atom.getIdentifier().equals("use_clause_literal") && 2 == atom.getArity()) {
literals.remove(atom);
} else {
if (grounding.getConfig().isFull() && grounding.hasDisplays() && grounding.lookup(atom))
model.remove(atom);
facts.remove(atom);
}
return this;
}
public Builder removeAtoms(Collection<Atom> atoms) {
if (null == atoms)
throw new IllegalArgumentException("Illegal 'indAtoms' argument in Hypothesis.Builder.removeAtoms(Collection<Atom>): " + atoms);
for (Atom atom : atoms)
removeAtom(atom);
return this;
}
}
private final Literal[] covered;
private final Grounding grounding;
private Clause[] hypotheses;
private final Atom[] literals;
private final Atom[] model;
private final Literal[] uncovered;
private Hypothesis(Builder builder) {
if (null == builder)
throw new IllegalArgumentException("Illegal 'builder' argument in Hypothesis(Hypothesis.Builder): " + builder);
this.covered = builder.covered.toArray(new Literal[builder.covered.size()]);
this.grounding = builder.grounding;
this.literals = builder.literals.toArray(new Atom[builder.literals.size()]);
this.model = builder.model.toArray(new Atom[builder.model.size()]);
this.uncovered = builder.uncovered.toArray(new Literal[builder.uncovered.size()]);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Hypothesis other = (Hypothesis) obj;
if (!Arrays.equals(hypotheses, other.hypotheses))
return false;
if (!Arrays.equals(covered, other.covered))
return false;
if (grounding == null) {
if (other.grounding != null)
return false;
} else if (!grounding.equals(other.grounding))
return false;
if (!Arrays.equals(literals, other.literals))
return false;
if (!Arrays.equals(model, other.model))
return false;
if (!Arrays.equals(uncovered, other.uncovered))
return false;
return true;
}
public final String[] getBackground() {
return grounding.getBackground();
}
public final Config getConfig() {
return grounding.getConfig();
}
public final Literal[] getCovered() {
return covered;
}
public final Atom[] getDelta() {
return grounding.getDelta();
}
public final Display[] getDisplays() {
return grounding.getDisplays();
}
public final String[] getDomains() {
return grounding.getDomains();
}
public final Example[] getExamples() {
return grounding.getExamples();
}
public final Clause[] getGeneralisation() {
return grounding.getGeneralisation();
}
public Grounding getGrounding() {
return grounding;
}
public final Clause[] getHypotheses() {
if (null == hypotheses) {
Set<Clause> set = new HashSet<>();
Clause[] generalisation = grounding.getGeneralisation();
Map<Integer, Clause.Builder> builders = new HashMap<>();
Map<Integer, Set<Literal>> types = new HashMap<>();
for (Atom atom : literals) {
int clauseId = ((Number) atom.getTerm(0)).getValue();
int literalId = ((Number) atom.getTerm(1)).getValue();
if (0 == literalId && 0 <= clauseId && clauseId < generalisation.length) {
builders.put(clauseId, new Clause.Builder().setHead(generalisation[clauseId].getHead()));
types.put(clauseId, new LinkedHashSet<>());
}
}
for (Atom atom : literals) {
int clauseId = ((Number) atom.getTerm(0)).getValue();
int literalId = ((Number) atom.getTerm(1)).getValue();
if (literalId > 0 && 0 <= clauseId && clauseId < generalisation.length) {
Literal literal = generalisation[clauseId].getBody(literalId);
builders.get(clauseId).addLiteral(literal);
Set<Literal> literals = types.get(clauseId);
for (Variable variable : literal.getVariables())
literals.add(new Literal.Builder( //
new Atom.Builder(variable.getType().getIdentifier()).addTerm(variable).build() //
).build());
}
}
for (int c : builders.keySet()) {
Clause.Builder builder = builders.get(c);
for (Literal literal : types.get(c))
builder.addLiteral(literal);
set.add(builder.build());
}
hypotheses = set.toArray(new Clause[set.size()]);
}
return hypotheses;
}
public final Clause[] getKernel() {
return grounding.getKernel();
}
public final ModeB[] getModeBs() {
return grounding.getModeBs();
}
public final ModeH[] getModeHs() {
return grounding.getModeHs();
}
public final Atom[] getModel() {
return model;
}
public final Problem getProblem() {
return grounding.getProblem();
}
public final Literal[] getUncovered() {
return uncovered;
}
public final boolean hasBackground() {
return grounding.hasBackground();
}
public final boolean hasCovered() {
return covered.length > 0;
}
public final boolean hasDelta() {
return grounding.hasDelta();
}
public final boolean hasDisplays() {
return grounding.hasDisplays();
}
public final boolean hasDomains() {
return grounding.getDomains().length > 0;
}
public final boolean hasExamples() {
return grounding.hasExamples();
}
public final boolean hasGeneralisation() {
return grounding.hasGeneralisation();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(hypotheses);
result = prime * result + Arrays.hashCode(covered);
result = prime * result + ((grounding == null) ? 0 : grounding.hashCode());
result = prime * result + Arrays.hashCode(literals);
result = prime * result + Arrays.hashCode(model);
result = prime * result + Arrays.hashCode(uncovered);
return result;
}
public final boolean hasHypotheses() {
return getHypotheses().length > 0;
}
public final boolean hasKernel() {
return grounding.hasKernel();
}
public final boolean hasModel() {
return model.length > 0;
}
public final boolean hasModes() {
return grounding.hasModes();
}
public final boolean hasUncovered() {
return uncovered.length > 0;
}
@Override
public Iterator<Atom> iterator() {
return new ArrayIterator<>(literals);
}
@Override
public String toString() {
return "Hypothesis [\n hypotheses=" + Arrays.toString(hypotheses) + ",\n covered=" + Arrays.toString(covered) + ",\n grounding=" + grounding
+ ",\n literals=" + Arrays.toString(literals) + ",\n model=" + Arrays.toString(model) + ",\n uncovered=" + Arrays.toString(uncovered)
+ "\n]";
}
}