package nars.language; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; import nars.storage.Memory; import nars.entity.Sentence; import nars.entity.TermLink; import nars.inference.TemporalRules; import nars.io.Symbols; /** * Static utility class for static methods related to Terms * @author me */ public class Terms { public static boolean equalSubTermsInRespectToImageAndProduct(final Term a, final Term b) { if (a == null || b == null) { return false; } if (!((a instanceof CompoundTerm) && (b instanceof CompoundTerm))) { return a.equals(b); } if (a instanceof Inheritance && b instanceof Inheritance) { return equalSubjectPredicateInRespectToImageAndProduct(a, b); } if (a instanceof Similarity && b instanceof Similarity) { return equalSubjectPredicateInRespectToImageAndProduct(a, b) || equalSubjectPredicateInRespectToImageAndProduct(b, a); } Term[] A = ((CompoundTerm) a).term; Term[] B = ((CompoundTerm) b).term; if (A.length != B.length) { return false; } else { for (int i = 0; i < A.length; i++) { Term x = A[i]; Term y = B[i]; if (!x.equals(y)) { if (x instanceof Inheritance && y instanceof Inheritance) { if (!equalSubjectPredicateInRespectToImageAndProduct(x, y)) { return false; } else { continue; } } if (x instanceof Similarity && y instanceof Similarity) { if (!equalSubjectPredicateInRespectToImageAndProduct(x, y) && !equalSubjectPredicateInRespectToImageAndProduct(y, x)) { return false; } else { continue; } } return false; } } return true; } } public static Term reduceUntilLayer2(final CompoundTerm _itself, Term replacement, Memory memory) { if (_itself == null) return null; Term reduced = reduceComponentOneLayer(_itself, replacement, memory); if (!(reduced instanceof CompoundTerm)) return null; CompoundTerm itself = (CompoundTerm)reduced; int j = 0; for (Term t : itself.term) { Term t2 = unwrapNegation(t); if (!(t2 instanceof Implication) && !(t2 instanceof Equivalence) && !(t2 instanceof Conjunction) && !(t2 instanceof Disjunction)) { j++; continue; } Term ret2 = reduceComponentOneLayer((CompoundTerm) t2, replacement, memory); //CompoundTerm itselfCompound = itself; Term replaced = null; if (j < itself.term.length ) replaced = itself.setComponent(j, ret2, memory); if (replaced != null) { if (replaced instanceof CompoundTerm) itself = (CompoundTerm)replaced; else return replaced; } j++; } return itself; } /* @Deprecated public static Term make(final String op, final ArrayList<Term> arg, final Memory memory) { final int length = op.length(); if (length == 1) { final char c = op.charAt(0); switch (c) { case Symbols.SET_EXT_OPENER: return SetExt.make(arg, memory); case Symbols.SET_INT_OPENER: return SetInt.make(arg, memory); case Symbols.INTERSECTION_EXT_OPERATORc: return IntersectionExt.make(arg, memory); case Symbols.INTERSECTION_INT_OPERATORc: return IntersectionInt.make(arg, memory); case Symbols.DIFFERENCE_EXT_OPERATORc: return DifferenceExt.make(arg, memory); case Symbols.DIFFERENCE_INT_OPERATORc: return DifferenceInt.make(arg, memory); case Symbols.PRODUCT_OPERATORc: return Product.make(arg, memory); case Symbols.IMAGE_EXT_OPERATORc: return ImageExt.make(arg, memory); case Symbols.IMAGE_INT_OPERATORc: return ImageInt.make(arg, memory); } } else if (length == 2) { //since these symbols are the same character repeated, we only need to compare the first character final char c1 = op.charAt(0); final char c2 = op.charAt(1); if (c1 == c2) { switch (c1) { case Symbols.NEGATION_OPERATORc: return Negation.make(arg, memory); case Symbols.DISJUNCTION_OPERATORc: return Disjunction.make(arg, memory); case Symbols.CONJUNCTION_OPERATORc: return Conjunction.make(arg, memory); } } else if (op.equals(Symbols.SEQUENCE_OPERATOR)) { return Conjunction.make(arg, TemporalRules.ORDER_FORWARD, memory); } else if (op.equals(Symbols.PARALLEL_OPERATOR)) { return Conjunction.make(arg, TemporalRules.ORDER_CONCURRENT, memory); } } throw new RuntimeException("Unknown Term operator: " + op); } */ /* static methods making new compounds, which may return null */ /** * Try to make a compound term from a template and a list of term * * @param compound The template * @param components The term * @param memory Reference to the memory * @return A compound term or null */ public static Term term(final CompoundTerm compound, final Term[] components) { if (compound instanceof ImageExt) { return new ImageExt(components, ((Image) compound).relationIndex); } else if (compound instanceof ImageInt) { return ImageInt.make(components, ((Image) compound).relationIndex); } else { return term(compound.operator(), components); } } public static Term term(final CompoundTerm compound, Collection<Term> components) { Term[] c = components.toArray(new Term[components.size()]); return term(compound, c); } /** * Try to make a compound term from an operator and a list of term * <p> * Called from StringParser * * @param op Term operator * @param arg Component list * @return A term or null */ public static Term term(final Symbols.NativeOperator op, final Term[] a) { switch (op) { case SET_EXT_OPENER: return SetExt.make(a); case SET_INT_OPENER: return SetInt.make(a); case INTERSECTION_EXT: return IntersectionExt.make(a); case INTERSECTION_INT: return IntersectionInt.make(a); case DIFFERENCE_EXT: return DifferenceExt.make(a); case DIFFERENCE_INT: return DifferenceInt.make(a); case INHERITANCE: return Inheritance.make(a[0], a[1]); case PRODUCT: return new Product(a); case IMAGE_EXT: return ImageExt.make(a); case IMAGE_INT: return ImageInt.make(a); case NEGATION: return Negation.make(a); case DISJUNCTION: return Disjunction.make(a); case CONJUNCTION: return Conjunction.make(a); case SEQUENCE: return Conjunction.make(a, TemporalRules.ORDER_FORWARD); case PARALLEL: return Conjunction.make(a, TemporalRules.ORDER_CONCURRENT); case IMPLICATION: return Implication.make(a[0], a[1]); case IMPLICATION_AFTER: return Implication.make(a[0], a[1], TemporalRules.ORDER_FORWARD); case IMPLICATION_BEFORE: return Implication.make(a[0], a[1], TemporalRules.ORDER_BACKWARD); case IMPLICATION_WHEN: return Implication.make(a[0], a[1], TemporalRules.ORDER_CONCURRENT); case EQUIVALENCE: return Equivalence.make(a[0], a[1]); case EQUIVALENCE_WHEN: return Equivalence.make(a[0], a[1], TemporalRules.ORDER_CONCURRENT); case EQUIVALENCE_AFTER: return Equivalence.make(a[0], a[1], TemporalRules.ORDER_FORWARD); } throw new RuntimeException("Unknown Term operator: " + op + " (" + op.name() + ")"); } /** * Try to remove a component from a compound * * @param t1 The compound * @param t2 The component * @param memory Reference to the memory * @return The new compound */ public static Term reduceComponents(final CompoundTerm t1, final Term t2, final Memory memory) { final Term[] list; if (t1.getClass() == t2.getClass()) { list = t1.cloneTermsExcept(true, ((CompoundTerm) t2).term); } else { list = t1.cloneTermsExcept(true, new Term[] { t2 }); } if (list != null) { if (list.length > 1) { return term(t1, list); } if (list.length == 1) { if ((t1 instanceof Conjunction) || (t1 instanceof Disjunction) || (t1 instanceof IntersectionExt) || (t1 instanceof IntersectionInt) || (t1 instanceof DifferenceExt) || (t1 instanceof DifferenceInt)) { return list[0]; } } } return null; } public static Term reduceComponentOneLayer(CompoundTerm t1, Term t2, Memory memory) { Term[] list; if (t1.getClass() == t2.getClass()) { list = t1.cloneTermsExcept(true, ((CompoundTerm) t2).term); } else { list = t1.cloneTermsExcept(true, new Term[] { t2 }); } if (list != null) { if (list.length > 1) { return term(t1, list); } else if (list.length == 1) { return list[0]; } } return t1; } public static Term unwrapNegation(final Term T) { if (T != null && T instanceof Negation) { return ((CompoundTerm) T).term[0]; } return T; } public static boolean equalSubjectPredicateInRespectToImageAndProduct(final Term a, final Term b) { if (a == null || b == null) { return false; } if (!(a instanceof Statement) && !(b instanceof Statement)) { return false; } if (a.equals(b)) { return true; } Statement A = (Statement) a; Statement B = (Statement) b; if (!(A instanceof Similarity && B instanceof Similarity || A instanceof Inheritance && B instanceof Inheritance)) return false; Term subjA = A.getSubject(); Term predA = A.getPredicate(); Term subjB = B.getSubject(); Term predB = B.getPredicate(); Term ta = null, tb = null; Term sa = null, sb = null; if ((subjA instanceof Product) && (predB instanceof ImageExt)) { ta = predA; sa = subjA; tb = subjB; sb = predB; } if ((subjB instanceof Product) && (predA instanceof ImageExt)) { ta = subjA; sa = predA; tb = predB; sb = subjB; } if ((predA instanceof ImageExt) && (predB instanceof ImageExt)) { ta = subjA; sa = predA; tb = subjB; sb = predB; } //DUPLICATE? /*if ((predA instanceof ImageExt) && (predB instanceof ImageExt)) { ta = subjA; sa = predA; tb = subjB; sb = predB; }*/ if ((subjA instanceof ImageInt) && (subjB instanceof ImageInt)) { ta = predA; sa = subjA; tb = predB; sb = subjB; } //ANOTHER DUPLICATE? /* if ((subjA instanceof ImageInt) && (subjB instanceof ImageInt)) { Set<Term> componentsA = new HashSet(); Set<Term> componentsB = new HashSet(); componentsA.add(predA); componentsB.add(predB); componentsA.addAll(Arrays.asList(((CompoundTerm) subjA).term)); componentsB.addAll(Arrays.asList(((CompoundTerm) subjB).term)); if (componentsA.containsAll(componentsB)) { return true; } } */ if ((predA instanceof Product) && (subjB instanceof ImageInt)) { ta = subjA; sa = predA; tb = predB; sb = subjB; } if ((predB instanceof Product) && (subjA instanceof ImageInt)) { ta = predA; sa = subjA; tb = subjB; sb = predB; } if (ta!=null) { Term[] sat = ((CompoundTerm)sa).term; Term[] sbt = ((CompoundTerm)sb).term; if(sa instanceof Image && sb instanceof Image) { Image im1=(Image) sa; Image im2=(Image) sb; if(im1.relationIndex != im2.relationIndex) { return false; } } Set<Term> componentsA = new HashSet(1+sat.length); Set<Term> componentsB = new HashSet(1+sbt.length); componentsA.add(ta); Collections.addAll(componentsA, sat); componentsB.add(tb); Collections.addAll(componentsB, sbt); for(Term sA : componentsA) { boolean had=false; for(Term sB : componentsB) { if(sA instanceof Variable && sB instanceof Variable) { if(sA.name.equals(sB.name)) { had=true; } } else if(sA.equals(sB)) { had=true; } } if(!had) { return false; } } return true; } return false; } /** * Collect TermLink templates into a list, go down one level except in * special cases * <p> * * @param componentLinks The list of TermLink templates built so far * @param type The type of TermLink to be built * @param term The CompoundTerm for which the links are built */ public static ArrayList<TermLink> prepareComponentLinks(final ArrayList<TermLink> componentLinks, final short type, final CompoundTerm t) { boolean tEquivalence = (t instanceof Equivalence); boolean tImplication = (t instanceof Implication); for (int i = 0; i < t.size(); i++) { Term t1 = t.term[i]; t1=new Sentence(t1,Symbols.TERM_NORMALIZING_WORKAROUND_MARK,null,null).term; if (!(t1 instanceof Variable)) { componentLinks.add(new TermLink(type, t1, i)); } if ((tEquivalence || (tImplication && (i == 0))) && ((t1 instanceof Conjunction) || (t1 instanceof Negation))) { prepareComponentLinks(componentLinks, TermLink.COMPOUND_CONDITION, (CompoundTerm) t1); } else if (t1 instanceof CompoundTerm) { final CompoundTerm ct1 = (CompoundTerm)t1; final int ct1Size = ct1.size(); //cache because this loop is critical boolean t1ProductOrImage = (t1 instanceof Product) || (t1 instanceof ImageExt) || (t1 instanceof ImageInt); for (int j = 0; j < ct1Size; j++) { Term t2 = ct1.term[j]; t2=new Sentence(t2,Symbols.TERM_NORMALIZING_WORKAROUND_MARK,null,null).term; if (!t2.hasVar()) { if (t1ProductOrImage) { if (type == TermLink.COMPOUND_CONDITION) { componentLinks.add(new TermLink(TermLink.TRANSFORM, t2, 0, i, j)); } else { componentLinks.add(new TermLink(TermLink.TRANSFORM, t2, i, j)); } } else { componentLinks.add(new TermLink(type, t2, i, j)); } } if ((t2 instanceof Product) || (t2 instanceof ImageExt) || (t2 instanceof ImageInt)) { CompoundTerm ct2 = (CompoundTerm)t2; final int ct2Size = ct2.size(); for (int k = 0; k < ct2Size; k++) { Term t3 = ct2.term[k]; t3=new Sentence(t3,Symbols.TERM_NORMALIZING_WORKAROUND_MARK,null,null).term; if (!t3.hasVar()) { if (type == TermLink.COMPOUND_CONDITION) { componentLinks.add(new TermLink(TermLink.TRANSFORM, t3, 0, i, j, k)); } else { componentLinks.add(new TermLink(TermLink.TRANSFORM, t3, i, j, k)); } } } } } } } return componentLinks; } public static ArrayList<TermLink> prepareComponentLinks(ArrayList<TermLink> componentLinks, CompoundTerm ct) { short type = (ct instanceof Statement) ? TermLink.COMPOUND_STATEMENT : TermLink.COMPOUND; // default return prepareComponentLinks(componentLinks, type, ct); } //TODO move this to a utility method public static <T> int indexOf(final T[] array, final T v) { /*if (v == null) { for (final T e : array) if (e == null) return true; } else {*/ int i = 0; for (final T e : array) { if (v.equals(e)) { return i; } i++; } return -1; } /** compres a set of terms (assumed to be unique) with another set to find if their * contents match. they can be in different order and still match. this is useful for * comparing whether compound terms in which order doesn't matter (ex: conjunction) * are equivalent. */ public static <T> boolean containsAll(final T[] a, final T[] b) { for (final T ax : a) { if (!contains(b, ax)) return false; } return true; } /** a contains any of b NOT TESTED YET */ public static boolean containsAny(final Term[] a, final Collection<Term> b) { for (final Term bx : b) { if (contains(a, bx)) return true; } for (final Term ax : a) { if (ax instanceof CompoundTerm) if (containsAny(((CompoundTerm)ax).term, b)) return true; } return false; } public static <T> boolean contains(final T[] array, final T v) { for (final T e : array) { if (v.equals(e)) { return true; } } return false; } static boolean equals(final Term[] a, final Term[] b) { if (a.length!=b.length) return false; for (int i = 0; i < a.length; i++) { if (!a[i].equals(b[i])) return false; } return true; } public static void verifyNonNull(Collection t) { for (Object o : t) if (o == null) throw new RuntimeException("Element null in: " + t); } static void verifyNonNull(Term... t) { for (Object o : t) if (o == null) throw new RuntimeException("Element null in: " + Arrays.toString(t)); } public static Term[] verifySortedAndUnique(final Term[] arg, boolean allowSingleton) { if (arg.length == 0) { throw new RuntimeException("Needs >0 components"); } if (!allowSingleton && (arg.length == 1)) { throw new RuntimeException("Needs >1 components: " + Arrays.toString(arg)); } Term[] s = Term.toSortedSetArray(arg); if (arg.length!=s.length) { throw new RuntimeException("Contains duplicates: " + Arrays.toString(arg)); } int j = 0; for (Term t : s) { if (!t.equals(arg[j++])) throw new RuntimeException("Un-ordered: " + Arrays.toString(arg) + " , correct order=" + Arrays.toString(s)); } return s; } /** * comparison that will match constant terms, allowing variables to match regardless * ex: (&&,<a --> b>,<b --> c>) also contains <a --> #1> */ static boolean containsVariablesAsWildcard(final Term[] term, final Term b) { CompoundTerm bCompound = (b instanceof CompoundTerm) ? ((CompoundTerm)b) : null; for (Term a : term) { if (a.equals(b)) return true; if ((a instanceof CompoundTerm) && (bCompound!=null)) { if (((CompoundTerm)a).equalsVariablesAsWildcards(bCompound)) return true; } } return false; } /** true if any of the terms contains a variable */ public static boolean containsVariables(Term... args) { for (Term t : args) { if (t.hasVar()) return true; } return false; } }