/** * */ package xhail.core.terms; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.apache.commons.collections4.iterators.ArrayIterator; import xhail.core.Buildable; /** * @author stefano * */ public class Atom implements Term, Iterable<Atom>, Comparable<Atom> { public static class Builder implements Buildable<Atom> { @Override public String toString() { return "Builder [identifier=" + identifier + ", terms=" + terms + ", scheme=" + scheme + ", weight=" + weight + ", priority=" + priority + "]"; } private String identifier; private int priority = 1; private SchemeTerm scheme = null; private List<Term> terms = new ArrayList<>(); private int weight = 1; public Builder(Atom atom) { if (null == atom) throw new IllegalArgumentException("Illegal 'atom' argument in Atom.Builder.Builder(Atom): " + atom); this.identifier = atom.identifier; this.priority = atom.priority; this.scheme = atom.scheme; this.terms = new ArrayList<>(); for (Term term : atom.terms) this.terms.add(term); this.weight = atom.weight; } public Builder(String identifier) { if (null == identifier || (identifier = identifier.trim()).isEmpty() || identifier.charAt(0) < 'a' || identifier.charAt(0) > 'z') throw new IllegalArgumentException("Illegal 'identifier' argument in Atom.Builder(String): " + identifier); this.identifier = identifier; } public Builder addTerm(Term term) { if (null == term) throw new IllegalArgumentException("Illegal 'term' argument in Atom.Builder.addTerm(Term): " + term); this.terms.add(term); return this; } public Builder addTerms(Collection<Term> terms) { if (null == terms) throw new IllegalArgumentException("Illegal 'terms' argument in Atom.Builder.addTerms(Collection<Term>): " + terms); this.terms.addAll(terms); return this; } public Builder addTerms(Term[] terms) { if (null == terms) throw new IllegalArgumentException("Illegal 'terms' argument in Atom.Builder.addTerms(Term[]): " + terms); for (Term term : terms) this.terms.add(term); return this; } @Override public Atom build() { return new Atom(this); } public Builder clearTerms() { this.terms.clear(); return this; } public Builder clone() { Builder result = new Builder(identifier).addTerms(terms).setWeight(weight).setPriority(priority); if (null != scheme) result.setScheme(scheme); return result; } public Builder removeTerm(Term term) { if (null == term) throw new IllegalArgumentException("Illegal 'term' argument in Atom.Builder.removeTerm(Term): " + term); this.terms.remove(term); return this; } public Builder removeTerms(Collection<Term> terms) { if (null == terms) throw new IllegalArgumentException("Illegal 'terms' argument in Atom.Builder.removeTerms(Collection<Term>): " + terms); this.terms.removeAll(terms); return this; } public Builder removeTerms(Term[] terms) { if (null == terms) throw new IllegalArgumentException("Illegal 'terms' argument in Atom.Builder.removeTerms(Term[]): " + terms); for (Term term : terms) this.terms.remove(term); return this; } public Builder setIdentifier(String identifier) { if (null == identifier || (identifier = identifier.trim()).isEmpty() || identifier.charAt(0) < 'a' || identifier.charAt(0) > 'z') throw new IllegalArgumentException("Illegal 'identifier' argument in Atom.Builder.setIdentifier(String): " + identifier); this.identifier = identifier; return this; } public Builder setPriority(int priority) { this.priority = priority; return this; } public Builder setScheme(SchemeTerm scheme) { if (null == scheme) throw new IllegalArgumentException("Illegal 'scheme' argument in Atom.Builder.addScheme(SchemeTerm): " + scheme); this.scheme = scheme; return this; } public Builder setWeight(int weight) { this.weight = weight; return this; } } private final String identifier; private final int priority; private final SchemeTerm scheme; private final Term[] terms; private final int weight; private Atom(Builder builder) { if (null == builder) throw new IllegalArgumentException("Illegal 'builder' argument in Atom(Atom.Builder): " + builder); this.identifier = builder.identifier; this.priority = builder.priority; this.scheme = builder.scheme; this.terms = builder.terms.toArray(new Term[builder.terms.size()]); this.weight = builder.weight; } @Override public int compareTo(Atom o) { int result = identifier.compareTo(o.identifier); if (0 == result) result = o.terms.length - terms.length; if (0 == result) for (int i = 0; 0 == result && i < terms.length; i++) result = o.terms[i].toString().compareTo(terms[i].toString()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Atom other = (Atom) obj; if (identifier == null) { if (other.identifier != null) return false; } else if (!identifier.equals(other.identifier)) return false; if (priority != other.priority) return false; if (scheme == null) { if (other.scheme != null) return false; } else if (!scheme.equals(other.scheme)) return false; if (!Arrays.equals(terms, other.terms)) return false; if (weight != other.weight) return false; return true; } // @Override // public Collection<Term> filters(SchemeTerm term) { // if (null == term) // throw new // IllegalArgumentException("Illegal 'term' argument in Atom.filter(SchemeTerm): " // + term); // if (term instanceof Placemarker) { // Placemarker other = (Placemarker) term; // if (other.getType() == Type.INPUT) // return Collections.singleton(this); // else // return Collections.emptySet(); // } else if (term instanceof Scheme) { // Scheme other = (Scheme) term; // if (!identifier.equals(other.getIdentifier()) || terms.length != // other.getArity()) // return null; // Set<Term> result = new HashSet<>(); // for (int i = 0; i < terms.length; i++) { // Collection<Term> nested = terms[i].filters(other.getTerm(i)); // if (null == nested) // return null; // result.addAll(nested); // } // return result; // } else // return null; // } public final int getArity() { return terms.length; } public final String getIdentifier() { return identifier; } public final int getPriority() { return priority; } public final SchemeTerm getScheme() { return scheme; } public final Term getTerm(int index) { if (index < 0 || index >= terms.length) throw new IndexOutOfBoundsException("Illegal 'index' argument in Atom.getTerm(int): " + index); return terms[index]; } public final Term[] getTerms() { return terms; } public final int getWeight() { return weight; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); result = prime * result + priority; result = prime * result + ((scheme == null) ? 0 : scheme.hashCode()); result = prime * result + Arrays.hashCode(terms); result = prime * result + weight; return result; } public boolean isPlacemarker() { return (Placemarker.CONSTANT_STRING.equals(identifier) || Placemarker.INPUT_STRING.equals(identifier) || Placemarker.OUTPUT_STRING.equals(identifier)) && 1 == terms.length; } @Override public Iterator<Atom> iterator() { return new ArrayIterator<>(terms); } // @Override // public Collection<Term> matches(SchemeTerm term, Collection<Term> // usables, Set<Atom> facts) { // if (null == term) // throw new // IllegalArgumentException("Illegal 'term' argument in Atom.matches(SchemeTerm, Collection<Term>, Set<Atom>): " // + term); // if (null == usables) // throw new // IllegalArgumentException("Illegal 'usables' argument in Atom.matches(SchemeTerm, Collection<Term>, Set<Atom>): " // + usables); // if (null == facts) // throw new // IllegalArgumentException("Illegal 'facts' argument in Atom.matches(SchemeTerm, Collection<Term>, Set<Atom>): " // + facts); // if (term instanceof Placemarker) { // Placemarker other = (Placemarker) term; // if (other.getType() == Type.INPUT) // if (usables.contains(this)) // return Collections.emptySet(); // else // return null; // else if (other.getType() == Type.OUTPUT) // return Collections.singleton(this); // else // return Collections.emptySet(); // } else if (term instanceof Scheme) { // Scheme other = (Scheme) term; // if (!identifier.equals(other.getIdentifier()) || terms.length != // other.getArity()) // return null; // Set<Term> result = new HashSet<>(); // for (int i = 0; i < terms.length; i++) { // Collection<Term> nested = terms[i].matches(other.getTerm(i), usables, // facts); // if (null == nested) // return null; // result.addAll(nested); // } // return result; // } else // return null; // } @Override public String toString() { String result = identifier; if (terms.length > 0) { result += "("; for (int i = 0; i < terms.length; i++) { if (i > 0) result += ","; result += terms[i].toString(); } result += ")"; } return result; } private final void getVariables(Set<Variable> result) { if (null == result) throw new IllegalArgumentException("Illegal 'result' argument in Atom.getVariables(Set<Variable>): " + result); for (Term term : terms) if (term instanceof Variable) result.add((Variable) term); else if (term instanceof Atom) ((Atom) term).getVariables(result); } private Variable[] variables; public final boolean hasVariables() { return getVariables().length > 0; } public final Variable[] getVariables() { if (null == variables) { Set<Variable> result = new LinkedHashSet<>(); getVariables(result); variables = result.toArray(new Variable[result.size()]); } return variables; } public final boolean hasTypes() { return getVariables().length > 0; } public final String[] getTypes() { int length = getVariables().length; String[] result = new String[length]; for (int i = 0; i < length; i++) result[i] = String.format("%s(%s)", variables[i].getType().getIdentifier(), variables[i].getIdentifier()); return result; } // public final String[] getVariables() { // int length = getPlacemarkers().length; // String[] result = new String[length]; // for (int i = 0; i < length; i++) // result[i] = String.format("V%d", 1 + i); // return result; // } }