From 8e80c32572d772c258aa5e6ad378f929972537ce Mon Sep 17 00:00:00 2001
From: peiwang <peiwang@LMC-025227.jpl.nasa.gov>
Date: Fri, 18 Jul 2014 12:20:51 -0700
Subject: [PATCH] input/output for temporal inference

---
 nars_java/nars/entity/Sentence.java           |  84 +++++++---
 nars_java/nars/entity/Stamp.java              |  57 ++++++-
 .../nars/inference/CompositionalRules.java    |   4 +-
 nars_java/nars/io/Symbols.java                |  21 ++-
 nars_java/nars/io/TextInput.java              |  24 ++-
 nars_java/nars/language/CompoundTerm.java     |  11 ++
 nars_java/nars/language/Conjunction.java      | 149 ++++++++++++++----
 nars_java/nars/language/Equivalence.java      |  61 +++++--
 nars_java/nars/language/Implication.java      |  59 ++++++-
 nars_java/nars/language/Interval.java         |  41 +++++
 nars_java/nars/language/Statement.java        |  15 ++
 nars_java/nars/storage/Memory.java            |  19 ++-
 12 files changed, 447 insertions(+), 98 deletions(-)
 create mode 100644 nars_java/nars/language/Interval.java

diff --git a/nars_java/nars/entity/Sentence.java b/nars_java/nars/entity/Sentence.java
index 2c86ca3..8c67f15 100644
--- a/nars_java/nars/entity/Sentence.java
+++ b/nars_java/nars/entity/Sentence.java
@@ -21,7 +21,9 @@
 package nars.entity;
 
 import nars.io.Symbols;
+import nars.language.Conjunction;
 import nars.language.Term;
+import nars.language.Variable;
 
 /**
  * A Sentence is an abstract class, mainly containing a Term, a TruthValue, and
@@ -49,7 +51,6 @@ public class Sentence implements Cloneable {
      */
     final public Stamp stamp;
 
-
     /**
      * Whether the sentence can be revised
      */
@@ -68,28 +69,16 @@ public class Sentence implements Cloneable {
      * base
      */
     public Sentence(Term content, char punctuation, TruthValue truth, Stamp stamp) {
-        this(content, punctuation, truth, stamp, true);
-    }
-
-    /**
-     * Create a Sentence with the given fields
-     *
-     * @param content The Term that forms the content of the sentence
-     * @param punctuation The punctuation indicating the type of the sentence
-     * @param truth The truth value of the sentence, null for question
-     * @param stamp The stamp of the sentence indicating its derivation time and
-     * base
-     * @param revisible Whether the sentence can be revised
-     */
-    public Sentence(Term content, char punctuation, TruthValue truth, Stamp stamp, boolean revisible) {
         this.content = content;
         this.content.renameVariables();
         this.punctuation = punctuation;
         this.truth = truth;
         this.stamp = stamp;
-        this.revisible = revisible;
-  
-                
+        if ((content instanceof Conjunction) && Variable.containVarDep(content.getName())) {
+            this.revisible = false;
+        } else {
+            this.revisible = true;
+        }
     }
 
     /**
@@ -145,7 +134,7 @@ public class Sentence implements Cloneable {
         if (truth == null) {
             return new Sentence((Term) content.clone(), punctuation, null, (Stamp) stamp.clone());
         }
-        return new Sentence((Term) content.clone(), punctuation, new TruthValue(truth), (Stamp) stamp.clone(), revisible);
+        return new Sentence((Term) content.clone(), punctuation, new TruthValue(truth), (Stamp) stamp.clone());
     }
 
     /**
@@ -175,7 +164,6 @@ public class Sentence implements Cloneable {
         return (Term) content.clone();
     }
 
-
     /**
      * Get the truth value of the sentence
      *
@@ -251,22 +239,66 @@ public class Sentence implements Cloneable {
     public String toKey() {
         if (key == null) {
             final String contentToString = content.toString();
-            final String truthString = truth!=null ? truth.toStringBrief() : null;
+            final String occurrenceTimeString = stamp.getOccurrenceTimeString();
+            final String truthString = truth != null ? truth.toStringBrief() : null;
             //final String stampString = stamp.toString();
 
             int stringLength = contentToString.length() + 1 + 1/* + stampString.length()*/;
-            if (truth!=null)
-                stringLength += truthString.length();
+            if (truth != null) {
+                stringLength += occurrenceTimeString.length() + truthString.length();
+            }
 
             final StringBuilder k = new StringBuilder(stringLength).append(contentToString)
-                .append(punctuation).append(" ");
+                    .append(punctuation).append(" ");
+            if (occurrenceTimeString.length() > 0) {
+                k.append(occurrenceTimeString);
+            }
             if (truth != null) {
                 k.append(truthString);
             }
 
-            key = k.toString();        
-            
+            key = k.toString();
+
         }
         return key;
     }
+
+    // need a separate display method, where the occurenceTime is converted to tense,
+    // according to the current time
+    /**
+     * Get a String representation of the sentence for display purpose
+     *
+     * @param currentTime Current time on the internal clock
+     * @return The String
+     */
+    public String display(long currentTime) {
+        final String contentToString = content.toString();
+        final long occurenceTime = stamp.getOccurrenceTime();
+        String tenseString = "";
+        if (occurenceTime != Stamp.ETERNAL) {
+            long timeDiff = occurenceTime - currentTime;
+            if (timeDiff > 0) {
+                tenseString = Symbols.TENSE_FUTURE;
+            } else if (timeDiff > 0) {
+                tenseString = Symbols.TENSE_PAST;
+            } else {
+                tenseString = Symbols.TENSE_PRESENT;
+            }
+        }
+        final String truthString = truth != null ? truth.toStringBrief() : null;
+        //final String stampString = stamp.toString();
+
+        int stringLength = contentToString.length() + tenseString.length() + 1 + 1/* + stampString.length()*/;
+        if (truth != null) {
+            stringLength += truthString.length();
+        }
+
+        final StringBuilder buffer = new StringBuilder(stringLength).append(contentToString)
+                .append(punctuation).append(" ").append(tenseString);
+        if (truth != null) {
+            buffer.append(truthString);
+        }
+        return buffer.toString();
+    }
+
 }
diff --git a/nars_java/nars/entity/Stamp.java b/nars_java/nars/entity/Stamp.java
index e7b6dff..04349da 100644
--- a/nars_java/nars/entity/Stamp.java
+++ b/nars_java/nars/entity/Stamp.java
@@ -57,6 +57,16 @@ public class Stamp implements Cloneable {
      */
     public final long creationTime;
 
+    /**
+     * estimated occurrence time of the event
+     */
+    public final long occurrenceTime;
+
+    /**
+     * default for atemporal events, means "always"
+     */
+    public static long ETERNAL = Integer.MIN_VALUE;
+
     /**
      * derivation chain containing the used premises and conclusions which made
      * deriving the conclusion c possible *
@@ -68,13 +78,22 @@ public class Stamp implements Cloneable {
      *
      * @param time Creation time of the stamp
      */
-    public Stamp(final long time) {
+    public Stamp(final long time, final String tense) {
         currentSerial++;
         baseLength = 1;
         evidentialBase = new long[baseLength];
         evidentialBase[0] = currentSerial;
         creationTime = time;
-        derivationChain = new ArrayList<Term>();
+        if (tense.length() == 0) {
+            occurrenceTime = ETERNAL;
+        } else if (tense.equals(Symbols.TENSE_PAST)) {
+            occurrenceTime = time - 1;
+        } else if (tense.equals(Symbols.TENSE_FUTURE)) {
+            occurrenceTime = time + 1;
+        } else { // if (tense.equals(Symbols.TENSE_PRESENT)) 
+            occurrenceTime = time;
+        }
+        derivationChain = new ArrayList<>();
     }
 
     /**
@@ -86,6 +105,7 @@ public class Stamp implements Cloneable {
         baseLength = old.length();
         evidentialBase = old.getBase();
         creationTime = old.getCreationTime();
+        occurrenceTime = old.getOccurrenceTime();
         derivationChain = old.getChain();
     }
 
@@ -102,6 +122,7 @@ public class Stamp implements Cloneable {
         baseLength = old.length();
         evidentialBase = old.getBase();
         creationTime = time;
+        occurrenceTime = old.getOccurrenceTime();
         derivationChain = old.getChain();
     }
 
@@ -153,7 +174,7 @@ public class Stamp implements Cloneable {
                     if (!derivationChain.contains(chain2.get(i2))) {
                         derivationChain.add(chain2.get(i2));
                     } else {
-                       j--; //was double, so we can add one more now
+                        j--; //was double, so we can add one more now
                     }
                     i2--;
                 }
@@ -163,6 +184,8 @@ public class Stamp implements Cloneable {
         Collections.reverse(derivationChain); //if jvm implements that correctly this is O(1)
 
         creationTime = time;
+        occurrenceTime = -1;    // to be revised
+
     }
 
     /**
@@ -325,6 +348,28 @@ public class Stamp implements Cloneable {
         return creationTime;
     }
 
+    /**
+     * Get the occurrenceTime of the truth-value
+     *
+     * @return The occurrence time
+     */
+    public long getOccurrenceTime() {
+        return occurrenceTime;
+    }
+
+    /**
+     * Get the occurrenceTime of the truth-value
+     *
+     * @return The occurrence time
+     */
+    public String getOccurrenceTimeString() {
+        if (occurrenceTime == ETERNAL) {
+            return "";
+        } else {
+            return "[" + occurrenceTime + "]";
+        }
+    }
+
     //String toStringCache = null; //holds pre-allocated string for toString()
     /**
      * Get a String form of the Stamp for display Format: {creationTime [:
@@ -364,7 +409,11 @@ public class Stamp implements Cloneable {
     public String toString() {
         final int estimatedInitialSize = 10 * (baseLength + derivationChain.size());
 
-        final StringBuilder buffer = new StringBuilder(estimatedInitialSize).append(" " + Symbols.STAMP_OPENER + creationTime);
+        final StringBuilder buffer = new StringBuilder(estimatedInitialSize);
+        buffer.append(" ").append(Symbols.STAMP_OPENER).append(creationTime);
+        if (occurrenceTime != ETERNAL) {
+            buffer.append('|').append(occurrenceTime);
+        }
         buffer.append(' ').append(Symbols.STAMP_STARTER).append(' ');
         for (int i = 0; i < baseLength; i++) {
             buffer.append(Long.toString(evidentialBase[i]));
diff --git a/nars_java/nars/inference/CompositionalRules.java b/nars_java/nars/inference/CompositionalRules.java
index 87e634c..be0923a 100644
--- a/nars_java/nars/inference/CompositionalRules.java
+++ b/nars_java/nars/inference/CompositionalRules.java
@@ -382,7 +382,7 @@ public final class CompositionalRules {
         content = Conjunction.make(state1, state2, memory);
         truth = TruthFunctions.intersection(truthT, truthB);
         budget = BudgetFunctions.compoundForward(truth, content, memory);
-        memory.doublePremiseTask(content, truth, budget, false);
+        memory.doublePremiseTask(content, truth, budget);
     }
 
     /**
@@ -424,7 +424,7 @@ public final class CompositionalRules {
         content.applySubstitute(substitute);
         TruthValue truth = TruthFunctions.intersection(taskSentence.getTruth(), belief.getTruth());
         BudgetValue budget = BudgetFunctions.forward(truth, memory);
-        memory.doublePremiseTask(content, truth, budget, false);
+        memory.doublePremiseTask(content, truth, budget);
         substitute.clear();
         substitute.put(commonTerm1, new Variable("$varInd1"));
         if (commonTerm2 != null) {
diff --git a/nars_java/nars/io/Symbols.java b/nars_java/nars/io/Symbols.java
index 2bcd5d0..174b418 100644
--- a/nars_java/nars/io/Symbols.java
+++ b/nars_java/nars/io/Symbols.java
@@ -31,6 +31,14 @@ public class Symbols {
     /* sentence type and delimitors */
     public static final char JUDGMENT_MARK = '.';
     public static final char QUESTION_MARK = '?';
+    public static final char GOAL_MARK = '!';
+    public static final char QUEST_MARK = '@';
+
+    /* Tense markers */
+    public static final String TENSE_MARK = ":";
+    public static final String TENSE_PAST = ":\\:";
+    public static final String TENSE_PRESENT = ":|:";
+    public static final String TENSE_FUTURE = ":/:";
 
     /* variable type */
     public static final char VAR_INDEPENDENT = '$';
@@ -71,7 +79,9 @@ public class Symbols {
         /* CompoundStatement operators, length = 2 */        
         NEGATION { @Override public String toString() { return "--"; } },
         DISJUNCTION { @Override public String toString() { return "||"; } },
-        CONJUNCTION { @Override public String toString() { return "&&"; } }    
+        CONJUNCTION { @Override public String toString() { return "&&"; } },    
+        SEQUENCE { @Override public String toString() { return "&/"; } },    
+        PARALLEL { @Override public String toString() { return "&|"; } }    
         
     }
     
@@ -98,6 +108,8 @@ public class Symbols {
     public static final char DISJUNCTION_OPERATORc = '|';
     public static final String CONJUNCTION_OPERATOR = "&&";
     public static final char CONJUNCTION_OPERATORc = '&';
+    public static final String SEQUENCE_OPERATOR = "&/";
+    public static final String PARALLEL_OPERATOR = "&|";
 
     public static enum Relation {
         INHERITANCE { @Override public String toString() { return "-->"; } },
@@ -106,7 +118,12 @@ public class Symbols {
         PROPERTY { @Override public String toString() { return "--]"; } },
         INSTANCE_PROPERTY { @Override public String toString() { return "{-]"; } },
         IMPLICATION { @Override public String toString() { return "==>"; } },
-        EQUIVALENCE { @Override public String toString() { return "<=>"; } }
+        IMPLICATION_AFTER { @Override public String toString() { return "=/>"; } },
+        IMPLICATION_WHEN { @Override public String toString() { return "=|>"; } },
+        IMPLICATION_BEFORE { @Override public String toString() { return "=\\>"; } },
+        EQUIVALENCE { @Override public String toString() { return "<=>"; } },
+        EQUIVALENCE_AFTER { @Override public String toString() { return "</>"; } },
+        EQUIVALENCE_WHEN { @Override public String toString() { return "<|>"; } }
     }
     
 
diff --git a/nars_java/nars/io/TextInput.java b/nars_java/nars/io/TextInput.java
index 50cf4fd..220db55 100644
--- a/nars_java/nars/io/TextInput.java
+++ b/nars_java/nars/io/TextInput.java
@@ -463,17 +463,18 @@ public class TextInput extends Symbols implements Input {
             Task task = null;
             String budgetString = getBudgetString(buffer);
             String truthString = getTruthString(buffer);
+            String tense = parseTense(buffer);
             String str = buffer.toString().trim();
             int last = str.length() - 1;
             char punc = str.charAt(last);
-            Stamp stamp = new Stamp(time);
+            Stamp stamp = new Stamp(time, tense);
             TruthValue truth = parseTruth(truthString, punc);
             Term content = parseTerm(str.substring(0, last), memory);
             if (content == null) throw new InvalidInputException("Content term missing");
             Sentence sentence = new Sentence(content, punc, truth, stamp);
-            if ((content instanceof Conjunction) && Variable.containVarDep(content.getName())) {
-                sentence.setRevisible(false);
-            }
+//            if ((content instanceof Conjunction) && Variable.containVarDep(content.getName())) {
+//                sentence.setRevisible(false);  // move to constructor?
+//            }
             BudgetValue budget = parseBudget(budgetString, punc, truth);
             task = new Task(sentence, budget);
             return task;
@@ -597,6 +598,21 @@ public class TextInput extends Symbols implements Input {
         return new BudgetValue(priority, durability, quality);
     }
 
+    /**
+     * Recognize the tense of an input sentence
+     * @param s the input in a StringBuffer
+     * @return a tense value
+     */
+    private static String parseTense(StringBuffer s) {
+        int i = s.indexOf(Symbols.TENSE_MARK);
+        String t = "";
+        if (i > 0) {
+            t = s.substring(i).trim();
+            s.delete(i, s.length());
+        }
+        return t;
+    }
+
     /* ---------- parse String into term ---------- */
     /**
      * Top-level method that parse a Term in general, which may recursively call
diff --git a/nars_java/nars/language/CompoundTerm.java b/nars_java/nars/language/CompoundTerm.java
index 59a2480..ebf1ff5 100644
--- a/nars_java/nars/language/CompoundTerm.java
+++ b/nars_java/nars/language/CompoundTerm.java
@@ -50,6 +50,11 @@ public abstract class CompoundTerm extends Term {
      * Whether the term names a concept
      */
     protected boolean isConstant = true;
+    
+    public static final int ORDER_FORWARD = 1;
+    public static final int ORDER_BACKWARD = -1;
+    public static final int ORDER_CONCURRENT = 0;
+    public static final int ORDER_NONE = Integer.MIN_VALUE;
 
     /* ----- abstract methods to be implemented in subclasses ----- */
     /**
@@ -247,6 +252,10 @@ public abstract class CompoundTerm extends Term {
                     case Symbols.CONJUNCTION_OPERATORc:
                         return Conjunction.make(arg, memory);
                 }            
+            } else if (op.equals(Symbols.SEQUENCE_OPERATOR)) {
+                return Conjunction.make(arg, ORDER_FORWARD, memory);
+            } else if (op.equals(Symbols.PARALLEL_OPERATOR)) {
+                return Conjunction.make(arg, ORDER_CONCURRENT, memory);
             }
         }
         throw new RuntimeException("Unknown Term operator: " + op);
@@ -286,6 +295,8 @@ public abstract class CompoundTerm extends Term {
                     case Symbols.CONJUNCTION_OPERATORc:
                         return true;                        
                 }            
+            } else if ((op.equals(Symbols.SEQUENCE_OPERATOR)) || (op.equals(Symbols.PARALLEL_OPERATOR))) {
+                return true;
             }
         }        
         
diff --git a/nars_java/nars/language/Conjunction.java b/nars_java/nars/language/Conjunction.java
index 9d4a8e0..bbee8d6 100644
--- a/nars_java/nars/language/Conjunction.java
+++ b/nars_java/nars/language/Conjunction.java
@@ -30,13 +30,22 @@ import nars.storage.Memory;
  */
 public class Conjunction extends CompoundTerm {
 
+    private int temporalOrder;
+
     /**
      * Constructor with partial values, called by make
      *
      * @param arg The component list of the term
      */
-    protected Conjunction(ArrayList<Term> arg) {
+//    protected Conjunction(ArrayList<Term> arg) {
+//        super(arg);
+//        temporalOrder = CompoundTerm.ORDER_NONE;
+//    }
+
+    private Conjunction(ArrayList<Term> arg, int order) {
         super(arg);
+        temporalOrder = order;
+        setName(makeName());
     }
 
     /**
@@ -47,8 +56,12 @@ public class Conjunction extends CompoundTerm {
      * @param con Whether the term is a constant
      * @param i Syntactic complexity of the compound
      */
-    private Conjunction(String n, ArrayList<Term> cs, boolean con, short i) {
+//    private Conjunction(String n, ArrayList<Term> cs, boolean con, short i) {
+//        super(n, cs, con, i);
+//    }
+    private Conjunction(String n, ArrayList<Term> cs, boolean con, short i, int order) {
         super(n, cs, con, i);
+        temporalOrder = order;
     }
 
     /**
@@ -58,7 +71,7 @@ public class Conjunction extends CompoundTerm {
      */
     @Override
     public Object clone() {
-        return new Conjunction(name, (ArrayList<Term>) cloneList(components), isConstant(), complexity);
+        return new Conjunction(name, cloneList(components), isConstant(), complexity, temporalOrder);
     }
 
     /**
@@ -68,7 +81,14 @@ public class Conjunction extends CompoundTerm {
      */
     @Override
     public String operator() {
-        return Symbols.CONJUNCTION_OPERATOR;
+        switch (temporalOrder) {
+            case CompoundTerm.ORDER_FORWARD:
+                return Symbols.SEQUENCE_OPERATOR;
+            case CompoundTerm.ORDER_CONCURRENT:
+                return Symbols.PARALLEL_OPERATOR;
+            default:
+                return Symbols.CONJUNCTION_OPERATOR;
+        }
     }
 
     /**
@@ -78,7 +98,11 @@ public class Conjunction extends CompoundTerm {
      */
     @Override
     public boolean isCommutative() {
-        return true;
+        if (temporalOrder == CompoundTerm.ORDER_FORWARD) {
+            return false;
+        } else {
+            return true;
+        }
     }
 
     /**
@@ -90,19 +114,41 @@ public class Conjunction extends CompoundTerm {
      * @param memory Reference to the memory
      */
     public static Term make(ArrayList<Term> argList, final Memory memory) {
-        
+
         //SETH asks: why is a term in the argList null
+        //Pei answers: that must be a bug to be fixed
         /*argList.removeIf(new Predicate<Term>() {
-            @Override public boolean test(Term t) {
-                return t==null;
-            }            
-        });*/
-         for (final Iterator<Term> itr = argList.iterator(); itr.hasNext();) {
-            if (itr.next() == null) { itr.remove(); }
+         @Override public boolean test(Term t) {
+         return t==null;
+         }            
+         });*/
+//        for (final Iterator<Term> itr = argList.iterator(); itr.hasNext();) {
+//            if (itr.next() == null) {
+//                itr.remove();
+//            }
+//        }
+//        final TreeSet<Term> set = new TreeSet<>(argList); // sort/merge arguments
+        return make(argList, CompoundTerm.ORDER_NONE, memory);
+    }
+
+    /**
+     * Try to make a new compound from a list of components. Called by
+     * StringParser.
+     *
+     * @param temporalOrder The temporal order among components
+     * @param argList the list of arguments
+     * @param memory Reference to the memory
+     * @return the Term generated from the arguments
+     */
+    public static Term make(ArrayList<Term> argList, int temporalOrder, final Memory memory) {
+        if (temporalOrder == ORDER_FORWARD) {
+            final String name = makeCompoundName(Symbols.SEQUENCE_OPERATOR, argList);
+            final Term t = memory.nameToListedTerm(name);
+            return (t != null) ? t : new Conjunction(argList, temporalOrder);
+        } else {
+            final TreeSet<Term> set = new TreeSet<>(argList);
+            return make(set, temporalOrder, memory);
         }
-        
-        final TreeSet<Term> set = new TreeSet<>(argList); // sort/merge arguments
-        return make(set, memory);
     }
 
     /**
@@ -113,7 +159,7 @@ public class Conjunction extends CompoundTerm {
      * @param memory Reference to the memory
      * @return the Term generated from the arguments
      */
-    private static Term make(final TreeSet<Term> set, final Memory memory) {
+    private static Term make(final TreeSet<Term> set, int temporalOrder, final Memory memory) {
         if (set.isEmpty()) {
             return null;
         }                         // special case: single component
@@ -121,9 +167,14 @@ public class Conjunction extends CompoundTerm {
             return set.first();
         }                         // special case: single component
         final ArrayList<Term> argument = new ArrayList<>(set);
-        final String name = makeCompoundName(Symbols.CONJUNCTION_OPERATOR, argument);
+        final String name;
+        if (temporalOrder == CompoundTerm.ORDER_NONE) {
+            name = makeCompoundName(Symbols.CONJUNCTION_OPERATOR, argument);
+        } else {
+            name = makeCompoundName(Symbols.PARALLEL_OPERATOR, argument);
+        }
         final Term t = memory.nameToListedTerm(name);
-        return (t != null) ? t : new Conjunction(argument);
+        return (t != null) ? t : new Conjunction(argument, temporalOrder);
     }
 
     // overload this method by term type?
@@ -137,23 +188,53 @@ public class Conjunction extends CompoundTerm {
      * @return A compound generated or a term it reduced to
      */
     public static Term make(final Term term1, final Term term2, final Memory memory) {
-        final TreeSet<Term> set;
-        if (term1 instanceof Conjunction) {
-            set = new TreeSet<>(((CompoundTerm) term1).cloneComponents());
-            if (term2 instanceof Conjunction) {
-                set.addAll(((CompoundTerm) term2).cloneComponents());
-            } // (&,(&,P,Q),(&,R,S)) = (&,P,Q,R,S)
-            else {
-                set.add((Term) term2.clone());
-            }                          // (&,(&,P,Q),R) = (&,P,Q,R)
-        } else if (term2 instanceof Conjunction) {
-            set = new TreeSet<>(((CompoundTerm) term2).cloneComponents());
-            set.add((Term) term1.clone());                              // (&,R,(&,P,Q)) = (&,P,Q,R)
+        return make(term1, term2, CompoundTerm.ORDER_NONE, memory);
+    }
+
+    public static Term make(final Term term1, final Term term2, int temporalOrder, final Memory memory) {
+        if (temporalOrder == CompoundTerm.ORDER_FORWARD) {
+            final ArrayList<Term> list;
+            if ((term1 instanceof Conjunction) && (((Conjunction) term1).getTemporalOrder() == CompoundTerm.ORDER_FORWARD)) {
+                list = new ArrayList<>(((CompoundTerm) term1).cloneComponents());
+                if ((term2 instanceof Conjunction) && (((Conjunction) term2).getTemporalOrder() == CompoundTerm.ORDER_FORWARD)) {
+                    list.addAll(((CompoundTerm) term2).cloneComponents());
+                } // (&/,(&/,P,Q),(&/,R,S)) = (&/,P,Q,R,S)
+                else {
+                    list.add((Term) term2.clone());
+                }                          // (&,(&,P,Q),R) = (&,P,Q,R)
+            } else if ((term2 instanceof Conjunction) && (((Conjunction) term2).getTemporalOrder() == CompoundTerm.ORDER_FORWARD)) {
+                list = new ArrayList<>(((CompoundTerm) term2).size() + 1);
+                list.add((Term) term1.clone());
+                list.addAll(((CompoundTerm) term2).cloneComponents()); // (&,R,(&,P,Q)) = (&,P,Q,R)
+            } else {
+                list = new ArrayList<>(2);
+                list.add((Term) term1.clone());
+                list.add((Term) term2.clone());
+            }
+            return make(list, temporalOrder, memory);
         } else {
-            set = new TreeSet<>();
-            set.add((Term) term1.clone());
-            set.add((Term) term2.clone());
+            final TreeSet<Term> set;
+            if (term1 instanceof Conjunction) {
+                set = new TreeSet<>(((CompoundTerm) term1).cloneComponents());
+                if (term2 instanceof Conjunction) {
+                    set.addAll(((CompoundTerm) term2).cloneComponents());
+                } // (&,(&,P,Q),(&,R,S)) = (&,P,Q,R,S)
+                else {
+                    set.add((Term) term2.clone());
+                }                          // (&,(&,P,Q),R) = (&,P,Q,R)
+            } else if (term2 instanceof Conjunction) {
+                set = new TreeSet<>(((CompoundTerm) term2).cloneComponents());
+                set.add((Term) term1.clone());                              // (&,R,(&,P,Q)) = (&,P,Q,R)
+            } else {
+                set = new TreeSet<>();
+                set.add((Term) term1.clone());
+                set.add((Term) term2.clone());
+            }
+            return make(set, temporalOrder, memory);
         }
-        return make(set, memory);
+    }
+
+    public int getTemporalOrder() {
+        return temporalOrder;
     }
 }
diff --git a/nars_java/nars/language/Equivalence.java b/nars_java/nars/language/Equivalence.java
index d2ca77e..7940893 100644
--- a/nars_java/nars/language/Equivalence.java
+++ b/nars_java/nars/language/Equivalence.java
@@ -30,42 +30,61 @@ import nars.storage.Memory;
  */
 public class Equivalence extends Statement {
 
+    private int temporalOrder = CompoundTerm.ORDER_NONE;
+
     /**
      * Constructor with partial values, called by make
+     *
      * @param components The component list of the term
      */
-    protected Equivalence(ArrayList<Term> components) {
+//    protected Equivalence(ArrayList<Term> components) {
+//        super(components);
+//    }
+    private Equivalence(ArrayList<Term> components, int order) {
         super(components);
+        temporalOrder = order;
     }
 
     /**
      * Constructor with full values, called by clone
+     *
      * @param n The name of the term
      * @param components Component list
      * @param constant Whether the statement contains open variable
      * @param complexity Syntactic complexity of the compound
      */
-    protected Equivalence(String n, ArrayList<Term> components, boolean constant, short complexity) {
+//    protected Equivalence(String n, ArrayList<Term> components, boolean constant, short complexity) {
+//        super(n, components, constant, complexity);
+//    }
+    private Equivalence(String n, ArrayList<Term> components, boolean constant, short complexity, int order) {
         super(n, components, constant, complexity);
+        temporalOrder = order;
     }
 
     /**
      * Clone an object
+     *
      * @return A new object
      */
     @Override
     public Object clone() {
-        return new Equivalence(name, (ArrayList<Term>) cloneList(components), isConstant(), complexity);
+        return new Equivalence(name, cloneList(components), isConstant(), complexity, temporalOrder);
     }
 
     /**
-     * Try to make a new compound from two components. Called by the inference rules.
+     * Try to make a new compound from two components. Called by the inference
+     * rules.
+     *
      * @param subject The first component
      * @param predicate The second component
      * @param memory Reference to the memory
      * @return A compound generated or null
      */
     public static Equivalence make(Term subject, Term predicate, Memory memory) {  // to be extended to check if subject is Conjunction
+        return make(subject, predicate, CompoundTerm.ORDER_NONE, memory);
+    }
+
+    public static Equivalence make(Term subject, Term predicate, int temporalOrder, Memory memory) {  // to be extended to check if subject is Conjunction
         if ((subject instanceof Implication) || (subject instanceof Equivalence)) {
             return null;
         }
@@ -75,35 +94,59 @@ public class Equivalence extends Statement {
         if (invalidStatement(subject, predicate)) {
             return null;
         }
-        if (subject.compareTo(predicate) > 0) {
+        if ((subject.compareTo(predicate) > 0) && (temporalOrder != CompoundTerm.ORDER_FORWARD)){
             Term interm = subject;
             subject = predicate;
             predicate = interm;
         }
-        String name = makeStatementName(subject, Symbols.Relation.EQUIVALENCE.toString(), predicate);
+        String copula;
+        switch (temporalOrder) {
+            case CompoundTerm.ORDER_FORWARD:
+                copula = Symbols.Relation.EQUIVALENCE_AFTER.toString();
+                break;
+            case CompoundTerm.ORDER_CONCURRENT:
+                copula = Symbols.Relation.EQUIVALENCE_WHEN.toString();
+                break;
+            default:
+                copula = Symbols.Relation.EQUIVALENCE.toString();
+        }                
+        String name = makeStatementName(subject, copula, predicate);
         Term t = memory.nameToListedTerm(name);
         if (t != null) {
             return (Equivalence) t;
         }
         ArrayList<Term> argument = argumentsToList(subject, predicate);
-        return new Equivalence(argument);
+        return new Equivalence(argument, temporalOrder);
     }
 
     /**
      * Get the operator of the term.
+     *
      * @return the operator of the term
      */
     @Override
     public String operator() {
-        return Symbols.Relation.EQUIVALENCE.toString();
+        switch (temporalOrder) {
+            case CompoundTerm.ORDER_FORWARD:
+                return Symbols.Relation.EQUIVALENCE_AFTER.toString();
+            case CompoundTerm.ORDER_CONCURRENT:
+                return Symbols.Relation.EQUIVALENCE_WHEN.toString();
+            default:
+                return Symbols.Relation.EQUIVALENCE.toString();
+        }
     }
 
     /**
      * Check if the compound is commutative.
+     *
      * @return true for commutative
      */
     @Override
     public boolean isCommutative() {
-        return true;
+        return (temporalOrder != CompoundTerm.ORDER_FORWARD);
+    }
+
+    public int getTemporalOrder() {
+        return temporalOrder;
     }
 }
diff --git a/nars_java/nars/language/Implication.java b/nars_java/nars/language/Implication.java
index 63425e5..b9383e6 100644
--- a/nars_java/nars/language/Implication.java
+++ b/nars_java/nars/language/Implication.java
@@ -26,16 +26,23 @@ import nars.io.Symbols;
 import nars.storage.Memory;
 
 /**
- * A Statement about an Inheritance relation.
+ * A Statement about an Inheritance copula.
  */
 public class Implication extends Statement {
 
+    private int temporalOrder = CompoundTerm.ORDER_NONE;
+
     /**
      * Constructor with partial values, called by make
      * @param arg The component list of the term
      */
-    protected Implication(ArrayList<Term> arg) {
+//    protected Implication(ArrayList<Term> arg) {
+//        super(arg);
+//    }
+
+    private Implication(ArrayList<Term> arg, int order) {
         super(arg);
+        temporalOrder = order;
     }
 
     /**
@@ -45,16 +52,22 @@ public class Implication extends Statement {
      * @param con Whether it is a constant term
      * @param i Syntactic complexity of the compound
      */
-    protected Implication(String n, ArrayList<Term> cs, boolean con, short i) {
+//    protected Implication(String n, ArrayList<Term> cs, boolean con, short i) {
+//        super(n, cs, con, i);
+//    }
+
+    private Implication(String n, ArrayList<Term> cs, boolean con, short i, int order) {
         super(n, cs, con, i);
+        temporalOrder = order;
     }
 
     /**
      * Clone an object
      * @return A new object
      */
+    @Override
     public Object clone() {
-        return new Implication(name, (ArrayList<Term>) cloneList(components), isConstant(), complexity);
+        return new Implication(name, cloneList(components), isConstant(), complexity, temporalOrder);
     }
 
     /**
@@ -65,6 +78,10 @@ public class Implication extends Statement {
      * @return A compound generated or a term it reduced to
      */
     public static Implication make(final Term subject, final Term predicate, final Memory memory) {
+        return make(subject, predicate, CompoundTerm.ORDER_NONE, memory);
+    }
+    
+    public static Implication make(final Term subject, final Term predicate, int temporalOrder, final Memory memory) {
         if ((subject == null) || (predicate == null)) {
             return null;
         }
@@ -74,7 +91,21 @@ public class Implication extends Statement {
         if (invalidStatement(subject, predicate)) {
             return null;
         }
-        final String name = makeStatementName(subject, Symbols.Relation.IMPLICATION.toString(), predicate);
+        String copula;
+        switch (temporalOrder) {
+            case CompoundTerm.ORDER_FORWARD:
+                copula = Symbols.Relation.IMPLICATION_AFTER.toString();
+                break;
+            case CompoundTerm.ORDER_CONCURRENT:
+                copula = Symbols.Relation.IMPLICATION_WHEN.toString();
+                break;
+            case CompoundTerm.ORDER_BACKWARD:
+                copula = Symbols.Relation.IMPLICATION_BEFORE.toString();
+                break;
+            default:
+                copula = Symbols.Relation.IMPLICATION.toString();
+        }                
+        final String name = makeStatementName(subject, copula, predicate);
         final Term t = memory.nameToListedTerm(name);
         if (t != null) {            
             if (t.getClass()!=Implication.class) {                
@@ -91,7 +122,7 @@ public class Implication extends Statement {
             return make(newCondition, ((Implication) predicate).getPredicate(), memory);
         } else {
             final ArrayList<Term> argument = argumentsToList(subject, predicate);
-            return new Implication(argument);
+            return new Implication(argument, temporalOrder);
         }
     }
 
@@ -99,7 +130,21 @@ public class Implication extends Statement {
      * Get the operator of the term.
      * @return the operator of the term
      */
+    @Override
     public String operator() {
-        return Symbols.Relation.IMPLICATION.toString();
+        switch (temporalOrder) {
+            case CompoundTerm.ORDER_FORWARD:
+                return Symbols.Relation.IMPLICATION_AFTER.toString();
+            case CompoundTerm.ORDER_CONCURRENT:
+                return Symbols.Relation.IMPLICATION_WHEN.toString();
+            case CompoundTerm.ORDER_BACKWARD:
+                return Symbols.Relation.IMPLICATION_BEFORE.toString();
+            default:
+                return Symbols.Relation.IMPLICATION.toString();
+        }
+    }
+    
+    public int getTemporalOrder() {
+        return temporalOrder;
     }
 }
diff --git a/nars_java/nars/language/Interval.java b/nars_java/nars/language/Interval.java
new file mode 100644
index 0000000..6c73e02
--- /dev/null
+++ b/nars_java/nars/language/Interval.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 peiwang
+ *
+ * This program 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.
+ *
+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package nars.language;
+
+/**
+ *
+ * @author peiwang
+ */
+public class Interval extends Term {
+    private int magnitude;
+
+    // time is a positive integer
+    public Interval(long time) {
+        name = "[" + magnitude + "]";
+        magnitude = (int) Math.floor(Math.log(time));
+    }
+    
+    public long getTime() {
+        return (long) Math.exp(magnitude);
+    }
+    
+    @Override
+    public Object clone() {
+        return new Interval(getTime());
+    }
+}
diff --git a/nars_java/nars/language/Statement.java b/nars_java/nars/language/Statement.java
index 48dee63..42bc293 100644
--- a/nars_java/nars/language/Statement.java
+++ b/nars_java/nars/language/Statement.java
@@ -92,9 +92,24 @@ public abstract class Statement extends CompoundTerm {
         if (relation == Relation.IMPLICATION) {
             return Implication.make(subject, predicate, memory);
         }
+        if (relation == Relation.IMPLICATION_AFTER) {
+            return Implication.make(subject, predicate, CompoundTerm.ORDER_FORWARD, memory);
+        }
+        if (relation == Relation.IMPLICATION_BEFORE) {
+            return Implication.make(subject, predicate, CompoundTerm.ORDER_BACKWARD, memory);
+        }
+        if (relation == Relation.IMPLICATION_WHEN) {
+            return Implication.make(subject, predicate, CompoundTerm.ORDER_CONCURRENT, memory);
+        }
         if (relation == Relation.EQUIVALENCE) {
             return Equivalence.make(subject, predicate, memory);
         }
+        if (relation == Relation.EQUIVALENCE_AFTER) {
+            return Equivalence.make(subject, predicate, CompoundTerm.ORDER_FORWARD, memory);
+        }
+        if (relation == Relation.EQUIVALENCE_WHEN) {
+            return Equivalence.make(subject, predicate, CompoundTerm.ORDER_CONCURRENT, memory);
+        }
         return null;
     }
 
diff --git a/nars_java/nars/storage/Memory.java b/nars_java/nars/storage/Memory.java
index e0af0be..0c7fe73 100644
--- a/nars_java/nars/storage/Memory.java
+++ b/nars_java/nars/storage/Memory.java
@@ -406,14 +406,14 @@ public class Memory {
      * @param newBudget The budget value in task
      * @param revisible Whether the sentence is revisible
      */
-    public void doublePremiseTask(Term newContent, TruthValue newTruth, BudgetValue newBudget, boolean revisible) {
-        if (newContent != null) {
-            Sentence taskSentence = currentTask.getSentence();
-            Sentence newSentence = new Sentence(newContent, taskSentence.getPunctuation(), newTruth, newStamp, revisible);
-            Task newTask = new Task(newSentence, newBudget, currentTask, currentBelief);
-            derivedTask(newTask, false, false);
-        }
-    }
+//    public void doublePremiseTask(Term newContent, TruthValue newTruth, BudgetValue newBudget) {
+//        if (newContent != null) {
+//            Sentence taskSentence = currentTask.getSentence();
+//            Sentence newSentence = new Sentence(newContent, taskSentence.getPunctuation(), newTruth, newStamp);
+//            Task newTask = new Task(newSentence, newBudget, currentTask, currentBelief);
+//            derivedTask(newTask, false, false);
+//        }
+//    }
 
     /**
      * Shared final operations by all single-premise rules, called in
@@ -447,8 +447,7 @@ public class Memory {
         } else {    // to answer a question with negation in NAL-5 --- move to activated task?
             newStamp = new Stamp(currentBelief.getStamp(), getTime());
         }
-
-        Sentence newSentence = new Sentence(newContent, punctuation, newTruth, newStamp, taskSentence.getRevisible());
+        Sentence newSentence = new Sentence(newContent, punctuation, newTruth, newStamp);
         Task newTask = new Task(newSentence, newBudget, currentTask, null);
         derivedTask(newTask, false, true);
     }
-- 
GitLab