Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
06/25/17 15:59:39 (7 years ago)
Author:
gkronber
Message:

#2581: merged r13645,r13648,r13650,r13651,r13652,r13654,r13657,r13658,r13659,r13661,r13662,r13669,r13708,r14142 from trunk to stable (to be deleted in the next commit)

Location:
stable
Files:
3 edited
1 copied

Legend:

Unmodified
Added
Removed
  • stable

  • stable/HeuristicLab.Algorithms.DataAnalysis

  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ConstraintHandler.cs

    r13645 r15060  
    22/* HeuristicLab
    33 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
    4  * and the BEACON Center for the Study of Evolution in Action.
    54 *
    65 * This file is part of HeuristicLab.
     
    2120#endregion
    2221
    23 
     22using System;
     23using System.Collections.Generic;
    2424using System.Diagnostics.Contracts;
     25using System.Linq;
    2526
    2627namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
    2728
    28   // more states for individual variables are created dynamically
     29  // This class restricts the set of allowed transitions of the automaton to prevent exploration of duplicate expressions.
     30  // It would be possible to implement this class in such a way that the search never visits a duplicate expression. However,
     31  // it seems very intricate to detect this robustly and in all cases while generating an expression because
     32  // some for of lookahead is necessary.
     33  // Instead the constraint handler only catches the obvious duplicates directly, but does not guarantee that the search always produces a valid expression.
     34  // The ratio of the number of unsuccessful searches, that need backtracking should be tracked in the MCTS alg (MctsSymbolicRegressionStatic)
     35
     36  // All changes to this class should be tested through unit tests. It is important that the ConstraintHandler is not too restrictive.
     37
     38  // the constraints are derived from a canonical form for expressions.
     39  // overall we can enforce a limited number of variable references
     40  //
     41  // an expression is a sum of terms t_1 ... t_n where terms are ordered according to a relation t_i (<=)_term t_j for each pair t_i, t_j and i <= j
     42  // a term is a product of factors where factors are ordered according to relation f_i (<=)_factor f_j for each pair f_i,f_j and i <= j
     43
     44  // we want to enforce lower-order terms before higher-order terms in expressions (based on number of variable references)
     45  // factors can have different types (variable, exp, log, inverse)
     46
     47  // (<=)_term  [IsSmallerOrEqualTerm(t_i, t_j)]
     48  //   1.  NumberOfVarRefs(t_i) < NumberOfVarRefs(t_j)  --> true           enforce terms with non-decreasing number of var refs
     49  //   2.  NumberOfVarRefs(t_i) > NumberOfVarRefs(t_j)  --> false
     50  //   3.  NumFactors(t_i) > NumFactors(t_j)            --> true           enforce terms with non-increasing number of factors
     51  //   4.  NumFactors(t_i) < NumFactors(t_j)            --> false
     52  //   5.  for all k factors: Factor(k, t_i) (<=)_factor  Factor(k, t_j) --> true // factors must be non-decreasing
     53  //   6.  all factors are (=)_factor                   --> true
     54  //   7.  else false
     55
     56  // (<=)_factor  [IsSmallerOrEqualFactor(f_i, f_j)]
     57  //   1.  FactorType(t_i) < FactorType(t_j)  --> true           enforce terms with non-decreasing factor type (var < exp < log < inv)
     58  //   2.  FactorType(t_i) > FactorType(t_j)  --> false
     59  //   3.  Compare the two factors specifically
     60  //     - variables: varIdx_i <= varIdx_j (only one var reference)
     61  //     - exp: number of variable references and then varIdx_i <= varIdx_j for each position
     62  //     - log: number of variable references and ...
     63  //     - inv: number of variable references and ...
     64  //
     65
     66  // for log and inverse factors we allow all polynomials as argument
     67  // a polynomial is a sum of terms t_1 ... t_n where terms are ordered according to a relation t_i (<=)_poly t_j for each pair t_i, t_j and i <= j
     68
     69  // (<=)_poly  [IsSmallerOrEqualPoly(t_i, t_j)]
     70  //  1. NumberOfVarRefs(t_i) < NumberOfVarRefs(t_j)         --> true // enforce non-decreasing number of var refs
     71  //  2. NumberOfVarRefs(t_i) > NumberOfVarRefs(t_j)         --> false // enforce non-decreasing number of var refs
     72  //  3. for all k variables: VarIdx(k,t_i) > VarIdx(k, t_j) --> false // enforce non-decreasing variable idx
     73
     74
     75  // we store the following to make comparsions:
     76  // - prevTerm (complete & containing all factors)
     77  // - curTerm  (incomplete & containing all completed factors)
     78  // - curFactor (incomplete)
    2979  internal class ConstraintHandler {
    3080    private int nVars;
    3181    private readonly int maxVariables;
    32 
    33     public int prevTermFirstVariableState;
    34     public int curTermFirstVariableState;
    35     public int prevTermFirstFactorType;
    36     public int curTermFirstFactorType;
    37     public int prevFactorType;
    38     public int curFactorType;
    39     public int prevFactorFirstVariableState;
    40     public int curFactorFirstVariableState;
    41     public int prevVariableRef;
     82    private bool invalidExpression;
     83
     84    public bool IsInvalidExpression {
     85      get { return invalidExpression; }
     86    }
     87
     88
     89    private TermInformation prevTerm;
     90    private TermInformation curTerm;
     91    private FactorInformation curFactor;
     92
     93
     94    private class TermInformation {
     95      public int numVarReferences { get { return factors.Sum(f => f.numVarReferences); } }
     96      public List<FactorInformation> factors = new List<FactorInformation>();
     97    }
     98
     99    private class FactorInformation {
     100      public int numVarReferences = 0;
     101      public int factorType; // use the state number to represent types
     102
     103      // for variable factors
     104      public int variableState = -1;
     105
     106      // for exp  factors
     107      public List<int> expVariableStates = new List<int>();
     108
     109      // for log and inv factors
     110      public List<List<int>> polyVariableStates = new List<List<int>>();
     111    }
    42112
    43113
     
    46116    }
    47117
    48     // 1) an expression is a sum of terms t_1 ... t_n
    49     //    FirstFactorType(t_i) <= FirstFactorType(t_j) for each pair t_i, t_j where i < j
    50     //    FirstVarReference(t_i) <= FirstVarReference(t_j) for each pair t_i, t_j where i < j and FirstFactorType(t_i) = FirstFactorType(t_j)
    51     // 2) a term is a product of factors, each factor is either a variable factor, an exp factor, a log factor or an inverse factor
    52     //    FactorType(f_i) <= FactorType(f_j) for each pair of factors f_i, f_j and i < j
    53     //    FirstVarReference(f_i) <= FirstVarReference(f_j) for each pair of factors f_i, f_j and i < j and FactorType(f_i) = FactorType(f_j)
    54     // 3) a variable factor is a product of variable references v1...vn
    55     //    VarIdx(v_i) <= VarIdx(v_j) for each pair of variable references v_i, v_j and i < j
    56     //    (IMPLICIT) FirstVarReference(t) <= VarIdx(v_i) for each variable reference v_i in term t
    57     // 4) an exponential factor is the exponential of a product of variables v1...vn
    58     //    VarIdx(v_i) <= VarIdx(v_j) for each pair of variable references v_i, v_j and i < j
    59     //    (IMPLICIT) FirstVarReference(t) <= VarIdx(v_i) for each variable reference v_i in term t
    60     // 5) a log factor is a sum of terms t_i where each term is a product of variables
    61     //    FirstVarReference(t_i) <= FirstVarReference(t_j) for each pair of terms t_i, t_j and i < j
    62     //    for each term t: VarIdx(v_i) <= VarIdx(v_j) for each pair of variable references v_i, v_j and i < j in t
     118    // the order relations for terms and factors
     119
     120    private static int CompareTerms(TermInformation a, TermInformation b) {
     121      if (a.numVarReferences < b.numVarReferences) return -1;
     122      if (a.numVarReferences > b.numVarReferences) return 1;
     123
     124      if (a.factors.Count > b.factors.Count) return -1;  // terms with more factors should be ordered first
     125      if (a.factors.Count < b.factors.Count) return +1;
     126
     127      var aFactors = a.factors.GetEnumerator();
     128      var bFactors = b.factors.GetEnumerator();
     129      while (aFactors.MoveNext() & bFactors.MoveNext()) {
     130        var c = CompareFactors(aFactors.Current, bFactors.Current);
     131        if (c < 0) return -1;
     132        if (c > 0) return 1;
     133      }
     134      // all factors are the same => terms are the same
     135      return 0;
     136    }
     137
     138    private static int CompareFactors(FactorInformation a, FactorInformation b) {
     139      if (a.factorType < b.factorType) return -1;
     140      if (a.factorType > b.factorType) return +1;
     141      // same factor types
     142      if (a.factorType == Automaton.StateVariableFactorStart) {
     143        return a.variableState.CompareTo(b.variableState);
     144      } else if (a.factorType == Automaton.StateExpFactorStart) {
     145        return CompareStateLists(a.expVariableStates, b.expVariableStates);
     146      } else {
     147        if (a.numVarReferences < b.numVarReferences) return -1;
     148        if (a.numVarReferences > b.numVarReferences) return +1;
     149        if (a.polyVariableStates.Count > b.polyVariableStates.Count) return -1; // more terms in the poly should be ordered first
     150        if (a.polyVariableStates.Count < b.polyVariableStates.Count) return +1;
     151        // log and inv
     152        var aTerms = a.polyVariableStates.GetEnumerator();
     153        var bTerms = b.polyVariableStates.GetEnumerator();
     154        while (aTerms.MoveNext() & bTerms.MoveNext()) {
     155          var c = CompareStateLists(aTerms.Current, bTerms.Current);
     156          if (c != 0) return c;
     157        }
     158        return 0; // all terms in the polynomial are the same
     159      }
     160    }
     161
     162    private static int CompareStateLists(List<int> a, List<int> b) {
     163      if (a.Count < b.Count) return -1;
     164      if (a.Count > b.Count) return +1;
     165      for (int i = 0; i < a.Count; i++) {
     166        if (a[i] < b[i]) return -1;
     167        if (a[i] > b[i]) return +1;
     168      }
     169      return 0; // all states are the same
     170    }
     171
     172
     173    private bool IsNewTermAllowed() {
     174      // next term must have at least as many variable references as the previous term
     175      return prevTerm == null || nVars + prevTerm.numVarReferences <= maxVariables;
     176    }
     177
     178    private bool IsNewFactorAllowed() {
     179      // next factor must have a larger or equal type compared to the previous factor.
     180      // if the types are the same it must have at least as many variable references.
     181      // so if the prevFactor is any other than invFactor (last possible type) then we only need to be able to add one variable
     182      // otherwise we need to be able to add at least as many variables as the previous factor
     183      return !curTerm.factors.Any() ||
     184             (nVars + curTerm.factors.Last().numVarReferences <= maxVariables);
     185    }
     186
     187    private bool IsAllowedAsNextFactorType(int followState) {
     188      // IsNewTermAllowed already ensures that we can add a term with enough variable references
     189
     190      // enforce constraints within terms (compare to prev factor)
     191      if (curTerm.factors.Any()) {
     192        // enforce non-decreasing factor types
     193        if (curTerm.factors.Last().factorType > followState) return false;
     194        // when the factor type is the same, starting a new factor is only allowed if we can add at least the number of variables of the prev factor
     195        if (curTerm.factors.Last().factorType == followState && nVars + curTerm.factors.Last().numVarReferences > maxVariables) return false;
     196      }
     197
     198      // enforce constraints on terms (compare to prev term)
     199      // meaning that we must ensure non-decreasing terms
     200      if (prevTerm != null) {
     201        // a factor type is only allowed if we can then produce a term that is larger or equal to the prev term
     202        // (1) if we the number of variable references still remaining is larger than the number of variable references in the prev term
     203        //     then it is always possible to build a larger term
     204        // (2) otherwise we try to build the largest possible term starting from current factors in the term.
     205        //     
     206
     207        var numVarRefsRemaining = maxVariables - nVars;
     208        Contract.Assert(!curTerm.factors.Any() || curTerm.factors.Last().numVarReferences <= numVarRefsRemaining);
     209
     210        if (prevTerm.numVarReferences < numVarRefsRemaining) return true;
     211
     212        // variable factors must be handled differently because they can only contain one variable reference
     213        if (followState == Automaton.StateVariableFactorStart) {
     214          // append the variable factor and the maximum possible state from the previous factor to create a larger factor
     215          var varF = CreateLargestPossibleFactor(Automaton.StateVariableFactorStart, 1);
     216          var maxF = CreateLargestPossibleFactor(prevTerm.factors.Max(f => f.factorType), numVarRefsRemaining - 1);
     217          var origFactorCount = curTerm.factors.Count;
     218          // add this factor to the current term
     219          curTerm.factors.Add(varF);
     220          curTerm.factors.Add(maxF);
     221          var c = CompareTerms(prevTerm, curTerm);
     222          // restore term
     223          curTerm.factors.RemoveRange(origFactorCount, 2);
     224          // if the prev term is still larger then this followstate is not allowed
     225          if (c > 0) {
     226            return false;
     227          }
     228        } else {
     229          var newF = CreateLargestPossibleFactor(followState, numVarRefsRemaining);
     230
     231          var origFactorCount = curTerm.factors.Count;
     232          // add this factor to the current term
     233          curTerm.factors.Add(newF);
     234          var c = CompareTerms(prevTerm, curTerm);
     235          // restore term
     236          curTerm.factors.RemoveAt(origFactorCount);
     237          // if the prev term is still larger then this followstate is not allowed
     238          if (c > 0) {
     239            return false;
     240          }
     241        }
     242      }
     243      return true;
     244    }
     245
     246    // largest possible factor of the given kind
     247    private FactorInformation CreateLargestPossibleFactor(int factorType, int numVarRefs) {
     248      var newF = new FactorInformation();
     249      newF.factorType = factorType;
     250      if (factorType == Automaton.StateVariableFactorStart) {
     251        newF.variableState = int.MaxValue;
     252        newF.numVarReferences = 1;
     253      } else if (factorType == Automaton.StateExpFactorStart) {
     254        for (int i = 0; i < numVarRefs; i++)
     255          newF.expVariableStates.Add(int.MaxValue);
     256        newF.numVarReferences = numVarRefs;
     257      } else if (factorType == Automaton.StateInvFactorStart || factorType == Automaton.StateLogFactorStart) {
     258        for (int i = 0; i < numVarRefs; i++) {
     259          newF.polyVariableStates.Add(new List<int>());
     260          newF.polyVariableStates[i].Add(int.MaxValue);
     261        }
     262        newF.numVarReferences = numVarRefs;
     263      }
     264      return newF;
     265    }
     266
     267    private bool IsAllowedAsNextVariableFactor(int variableState) {
     268      Contract.Assert(variableState >= Automaton.FirstDynamicState);
     269      return !curTerm.factors.Any() || curTerm.factors.Last().variableState <= variableState;
     270    }
     271
     272    private bool IsAllowedAsNextInExp(int variableState) {
     273      Contract.Assert(variableState >= Automaton.FirstDynamicState);
     274      if (curFactor.expVariableStates.Any() && curFactor.expVariableStates.Last() > variableState) return false;
     275      if (curTerm.factors.Any()) {
     276        // try and compare with prev factor     
     277        curFactor.numVarReferences++;
     278        curFactor.expVariableStates.Add(variableState);
     279        var c = CompareFactors(curTerm.factors.Last(), curFactor);
     280        curFactor.numVarReferences--;
     281        curFactor.expVariableStates.RemoveAt(curFactor.expVariableStates.Count - 1);
     282        return c <= 0;
     283      }
     284      return true;
     285    }
     286
     287    private bool IsNewTermAllowedInPoly() {
     288      return nVars + curFactor.polyVariableStates.Last().Count() <= maxVariables;
     289    }
     290
     291    private bool IsAllowedAsNextInPoly(int variableState) {
     292      Contract.Assert(variableState >= Automaton.FirstDynamicState);
     293      return !curFactor.polyVariableStates.Any() ||
     294             !curFactor.polyVariableStates.Last().Any() ||
     295              curFactor.polyVariableStates.Last().Last() <= variableState;
     296    }
     297    private bool IsTermCompleteInPoly() {
     298      var nTerms = curFactor.polyVariableStates.Count;
     299      return nTerms == 1 ||
     300             curFactor.polyVariableStates[nTerms - 2].Count <= curFactor.polyVariableStates[nTerms - 1].Count;
     301
     302    }
     303    private bool IsCompleteExp() {
     304      return !curTerm.factors.Any() || CompareFactors(curTerm.factors.Last(), curFactor) <= 0;
     305    }
     306
    63307    public bool IsAllowedFollowState(int currentState, int followState) {
    64       // the following states are always allowed
     308      // an invalid action was taken earlier on => nothing can be done anymore
     309      if (invalidExpression) return false;
     310      // states that have no alternative are always allowed
     311      // some ending states are only allowed if enough variables have been used in the term
    65312      if (
    66         followState == Automaton.StateVariableFactorEnd ||
    67         followState == Automaton.StateExpFEnd ||
    68         followState == Automaton.StateExpFactorEnd ||
    69         followState == Automaton.StateLogTFEnd ||
    70         followState == Automaton.StateLogTEnd ||
    71         followState == Automaton.StateLogFactorEnd ||
    72         followState == Automaton.StateInvTFEnd ||
    73         followState == Automaton.StateInvTEnd ||
    74         followState == Automaton.StateInvFactorEnd ||
    75         followState == Automaton.StateFactorEnd ||
    76         followState == Automaton.StateTermEnd ||
    77         followState == Automaton.StateExprEnd
     313        currentState == Automaton.StateTermStart ||           // no alternative
     314        currentState == Automaton.StateExpFactorStart ||
     315        currentState == Automaton.StateLogFactorStart ||
     316        currentState == Automaton.StateInvFactorStart ||
     317        followState == Automaton.StateVariableFactorEnd ||    // no alternative
     318        followState == Automaton.StateExpFEnd ||              // no alternative
     319        followState == Automaton.StateLogTFEnd ||             // no alternative
     320        followState == Automaton.StateInvTFEnd ||             // no alternative
     321        followState == Automaton.StateFactorEnd ||            // always allowed because no alternative
     322        followState == Automaton.StateExprEnd                 // we could also constrain the minimum number of terms here
    78323      ) return true;
    79324
    80325
    81       // all other states are only allowed if we can add more variables
    82       if (nVars >= maxVariables) return false;
    83 
    84       // the following states are always allowed when we can add more variables
     326      // starting a new term is only allowed if we can add a term with at least the number of variables of the prev term
     327      if (followState == Automaton.StateTermStart && !IsNewTermAllowed()) return false;
     328      if (followState == Automaton.StateFactorStart && !IsNewFactorAllowed()) return false;
     329      if (currentState == Automaton.StateFactorStart && !IsAllowedAsNextFactorType(followState)) return false;
     330      if (followState == Automaton.StateTermEnd && prevTerm != null && CompareTerms(prevTerm, curTerm) > 0) return false;
     331
     332      // all of these states add at least one variable
    85333      if (
    86         followState == Automaton.StateTermStart ||
    87         followState == Automaton.StateFactorStart ||
    88         followState == Automaton.StateExpFStart ||
    89         followState == Automaton.StateLogTStart ||
    90         followState == Automaton.StateLogTFStart ||
    91         followState == Automaton.StateInvTStart ||
    92         followState == Automaton.StateInvTFStart
    93         ) return true;
    94 
    95       // enforce non-decreasing factor types
    96       if (currentState == Automaton.StateFactorStart) {
    97         if (curFactorType < 0) {
    98           //    FirstFactorType(t_i) <= FirstFactorType(t_j) for each pair t_i, t_j where i < j
    99           return prevTermFirstFactorType <= followState;
    100         } else {
    101           // FactorType(f_i) <= FactorType(f_j) for each pair of factors f_i, f_j and i < j
    102           return curFactorType <= followState;
    103         }
    104       }
    105       // enforce non-decreasing variables references in variable and exp factors
    106       if (currentState == Automaton.StateVariableFactorStart || currentState == Automaton.StateExpFStart || currentState == Automaton.StateLogTFStart || currentState == Automaton.StateInvTFStart) {
    107         if (prevVariableRef > followState) return false; // never allow decreasing variables
    108         if (prevFactorType < 0) {
    109           // FirstVarReference(t_i) <= FirstVarReference(t_j) for each pair t_i, t_j where i < j
    110           return prevTermFirstVariableState <= followState;
    111         } else if (prevFactorType == curFactorType) {
    112           // (FirstVarReference(f_i) <= FirstVarReference(f_j) for each pair of factors f_i, f_j and i < j and FactorType(f_i) = FactorType(f_j)
    113           return prevFactorFirstVariableState <= followState;
    114         }
    115       }
    116 
    117 
    118       return true;
     334          followState == Automaton.StateVariableFactorStart ||
     335          followState == Automaton.StateExpFactorStart || followState == Automaton.StateExpFStart ||
     336          followState == Automaton.StateLogFactorStart || followState == Automaton.StateLogTStart ||
     337          followState == Automaton.StateLogTFStart ||
     338          followState == Automaton.StateInvFactorStart || followState == Automaton.StateInvTStart ||
     339          followState == Automaton.StateInvTFStart) {
     340        if (nVars + 1 > maxVariables) return false;
     341      }
     342
     343      if (currentState == Automaton.StateVariableFactorStart && !IsAllowedAsNextVariableFactor(followState)) return false;
     344      else if (currentState == Automaton.StateExpFStart && !IsAllowedAsNextInExp(followState)) return false;
     345      else if (followState == Automaton.StateLogTStart && !IsNewTermAllowedInPoly()) return false;
     346      else if (currentState == Automaton.StateLogTFStart && !IsAllowedAsNextInPoly(followState)) return false;
     347      else if (followState == Automaton.StateInvTStart && !IsNewTermAllowedInPoly()) return false;
     348      else if (currentState == Automaton.StateInvTFStart && !IsAllowedAsNextInPoly(followState)) return false;
     349      // finishing an exponential factor is only allowed when the number of variable references is large enough
     350      else if (followState == Automaton.StateExpFactorEnd && !IsCompleteExp()) return false;
     351      // finishing a polynomial (in log or inv) is only allowed when the number of variable references is large enough
     352      else if (followState == Automaton.StateInvTEnd && !IsTermCompleteInPoly()) return false;
     353      else if (followState == Automaton.StateLogTEnd && !IsTermCompleteInPoly()) return false;
     354
     355      else if (nVars > maxVariables) return false;
     356      else return true;
    119357    }
    120358
     
    122360    public void Reset() {
    123361      nVars = 0;
    124 
    125 
    126       prevTermFirstVariableState = -1;
    127       curTermFirstVariableState = -1;
    128       prevTermFirstFactorType = -1;
    129       curTermFirstFactorType = -1;
    130       prevVariableRef = -1;
    131       prevFactorType = -1;
    132       curFactorType = -1;
    133       curFactorFirstVariableState = -1;
    134       prevFactorFirstVariableState = -1;
     362      prevTerm = null;
     363      curTerm = null;
     364      curFactor = null;
     365      invalidExpression = false;
    135366    }
    136367
    137368    public void StartTerm() {
    138       // reset factor type. in each term we can start with each type of factor
    139       prevTermFirstVariableState = curTermFirstVariableState;
    140       curTermFirstVariableState = -1;
    141 
    142       prevTermFirstFactorType = curTermFirstFactorType;
    143       curTermFirstFactorType = -1;
    144 
    145 
    146       prevFactorType = -1;
    147       curFactorType = -1;
    148 
    149       curFactorFirstVariableState = -1;
    150       prevFactorFirstVariableState = -1;
     369      curTerm = new TermInformation();
    151370    }
    152371
    153372    public void StartFactor(int state) {
    154       prevFactorType = curFactorType;
    155       curFactorType = -1;
    156 
    157       prevFactorFirstVariableState = curFactorFirstVariableState;
    158       curFactorFirstVariableState = -1;
    159 
    160 
    161       // store the first factor type
    162       if (curTermFirstFactorType < 0) {
    163         curTermFirstFactorType = state;
    164       }
    165       curFactorType = state;
    166 
    167       // reset variable references. in each factor we can start with each variable reference
    168       prevVariableRef = -1;
     373      curFactor = new FactorInformation();
     374      curFactor.factorType = state;
    169375    }
    170376
    171377
    172378    public void AddVarToCurrentFactor(int state) {
    173 
    174       Contract.Assert(prevVariableRef <= state);
    175 
    176       // store the first variable reference for each factor
    177       if (curFactorFirstVariableState < 0) {
    178         curFactorFirstVariableState = state;
    179 
    180         // store the first variable reference for each term
    181         if (curTermFirstVariableState < 0) {
    182           curTermFirstVariableState = state;
    183         }
    184       }
    185       prevVariableRef = state;
     379      Contract.Assert(Automaton.FirstDynamicState <= state);
     380      Contract.Assert(curTerm != null);
     381      Contract.Assert(curFactor != null);
    186382
    187383      nVars++;
     384      curFactor.numVarReferences++;
     385
     386      if (curFactor.factorType == Automaton.StateVariableFactorStart) {
     387        Contract.Assert(curFactor.variableState < 0); // not set before
     388        curFactor.variableState = state;
     389      } else if (curFactor.factorType == Automaton.StateExpFactorStart) {
     390        curFactor.expVariableStates.Add(state);
     391      } else if (curFactor.factorType == Automaton.StateLogFactorStart ||
     392                 curFactor.factorType == Automaton.StateInvFactorStart) {
     393        curFactor.polyVariableStates.Last().Add(state);
     394      } else throw new InvalidProgramException();
     395    }
     396
     397    public void StartNewTermInPoly() {
     398      curFactor.polyVariableStates.Add(new List<int>());
    188399    }
    189400
    190401    public void EndFactor() {
    191       Contract.Assert(prevFactorFirstVariableState <= curFactorFirstVariableState);
    192       Contract.Assert(prevFactorType <= curFactorType);
     402      // enforce non-decreasing factors
     403      if (curTerm.factors.Any() && CompareFactors(curTerm.factors.Last(), curFactor) > 0)
     404        invalidExpression = true;
     405      curTerm.factors.Add(curFactor);
     406      curFactor = null;
    193407    }
    194408
    195409    public void EndTerm() {
    196 
    197       Contract.Assert(prevFactorType <= curFactorType);
    198       Contract.Assert(prevTermFirstVariableState <= curTermFirstVariableState);
     410      // enforce non-decreasing terms (TODO: equal terms should not be allowed)
     411      if (prevTerm != null && CompareTerms(prevTerm, curTerm) > 0)
     412        invalidExpression = true;
     413      prevTerm = curTerm;
     414      curTerm = null;
    199415    }
    200416  }
Note: See TracChangeset for help on using the changeset viewer.