- Timestamp:
- 02/09/15 09:48:30 (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/HeuristicLab.Problems.GrammaticalOptimization/HeuristicLab.Common/ExpressionExtender.cs
r11966 r11972 49 49 } 50 50 51 // an expression is a list of terms51 // an expression is a sorted set of terms 52 52 // a term is an (ordered) list of factors 53 // a factor is asymbol or an inverted expression53 // a factor is either a single symbol or an inverted expression 54 54 // CanonicalExpression reads multiple terms (expressions) and must merge the terms in the expression (ordering and duplicates) 55 55 // CanonicalTerm reads multiple factors and must expand factors whenever it reads a combined factor (expression) it produces an expression … … 83 83 // canonical term returns either a single term (product of factors) or a set of terms 84 84 private Expr CanonicalTerm() { 85 var factors = new List<Expr>(); 86 var invFactors = new List<Expr>(); 85 var factors = new List<Factor>(); 87 86 var f = CanonicalFact(); 88 87 if (f != null) factors.Add(f); … … 97 96 f = CanonicalFact(); 98 97 f.Invert(); 99 if (f != null) invFactors.Add(f);98 if (f != null) factors.Add(f); 100 99 } 101 100 curSy = CurSy(); 102 101 } 103 104 // cancellation 105 foreach (var invF in invFactors.ToArray()) { 106 invF.Invert(); 107 if (factors.Contains(invF)) { 108 invFactors.Remove(invF); 109 factors.Remove(invF); 110 if (factors.Count == 0) factors.Add(new Expr(new Term('1'))); 111 } else invF.Invert(); 112 } 113 114 return ExpandFactors(factors, invFactors); 115 } 116 117 private Expr ExpandFactors(List<Expr> factors, List<Expr> invFactors) { 102 return ExpandFactors(factors); 103 } 104 105 /* 106 private List<Factor> CancelFactors(Term t) { 107 var nonInvF = t.Factors.Where(f => !f.IsInverse).ToArray(); 108 var invF = t.Factors.Where(f => f.IsInverse).ToArray(); 109 110 var result = new List<Factor>(); 111 foreach (var f in nonInvF) { 112 if (!invF.Contains(f)) { 113 result.Add(f); 114 } 115 } 116 if (result.Count == 0) result.Add(new Factor('1')); 117 return result; 118 } 119 */ 120 // canonical fact returns a factor (either a singe variable, or a set of terms) 121 private Factor CanonicalFact() { 122 var curSy = CurSy(); 123 if (curSy == '!') { 124 throw new NotSupportedException(); 125 } else if (curSy == '(') { 126 NewSy(); 127 Expr r = CanonicalExpr(); // this is already simplified 128 if (CurSy() != ')') throw new ArgumentException(); 129 NewSy(); 130 return new Factor(r); 131 } else if (curSy >= 'a' && curSy <= 'z') { 132 NewSy(); 133 return new Factor(curSy); 134 // } else if (curSy >= '0' && curSy <= '9') { 135 } else if (curSy >= 'A' && curSy <= 'Z') { 136 // treat nonterminals in the same way as variables 137 NewSy(); 138 return new Factor(curSy); 139 140 } else throw new ArgumentException("found symbol " + curSy); 141 } 142 143 // a list of factors (symbols, or expressions, and possibly inverses are read 144 // a lis to factors symbols or expressions and possibly inverses are produced 145 // all non-inverse expression factors are expanded 146 private Expr ExpandFactors(IEnumerable<Factor> factors) { 118 147 // if (invFactors.Count > 0) throw new NotImplementedException(); 119 Expr currentFact = factors.First(); // new Expr(simpleFactor)); 120 Debug.Assert(!currentFact.Inverse); // the first factor is never an inverted factor 148 Debug.Assert(!factors.First().IsInverse); // the first factor is never an inverted factor 149 150 // each factor could be a list of terms (expression) 151 152 Expr currentFact = null; 153 var firstFactor = factors.First(); 154 if (firstFactor.IsSimpleFactor) currentFact = new Expr(new Term(firstFactor)); 155 else currentFact = firstFactor.Expr; 156 121 157 foreach (var fact in factors.Skip(1)) { 122 currentFact = AllProducts(currentFact, fact);123 }124 foreach (var invF in invFactors) {125 currentFact = All InvProducts(currentFact, invF);158 Expr curExpr = null; 159 if (fact.IsSimpleFactor || fact.IsInverse) curExpr = new Expr(new Term(fact)); 160 else curExpr = fact.Expr; 161 currentFact = AllProducts(currentFact, curExpr); 126 162 } 127 163 return currentFact; … … 133 169 var combs = from aT in aTerms 134 170 from bT in bTerms 135 select new Term(aT.Symbols.Concat(bT.Symbols), aT.InvExpressions.Concat(bT.InvExpressions)); 171 let factors = CancelFactors(aT.Factors.Concat(bT.Factors)) 172 select new Term(factors); 136 173 return new Expr(combs); 137 174 } 138 175 139 private Expr AllInvProducts(Expr a, Expr b) { 140 var aTerms = a.Terms.ToArray(); 141 var combs = from aT in aTerms 142 select new Term(aT.Symbols, aT.InvExpressions.Concat(new Expr[] { b })); 143 return new Expr(combs); 144 } 145 146 // canonical fact returns a factor (either a singe variable, or a set of terms) 147 private Expr CanonicalFact() { 148 var curSy = CurSy(); 149 if (curSy == '!') { 150 throw new NotSupportedException(); 151 } else if (curSy == '(') { 152 NewSy(); 153 Expr r = CanonicalExpr(); 154 if (CurSy() != ')') throw new ArgumentException(); 155 NewSy(); 156 return r; 157 } else if (curSy >= 'a' && curSy <= 'z') { 158 NewSy(); 159 return new Expr(new Term(curSy)); 160 // } else if (curSy >= '0' && curSy <= '9') { 161 } else if (curSy >= 'A' && curSy <= 'Z') { 162 // treat nonterminals in the same way as variables 163 NewSy(); 164 return new Expr(new Term(curSy)); 165 166 } else throw new ArgumentException("found symbol " + curSy); 176 private IEnumerable<Factor> CancelFactors(IEnumerable<Factor> factors) { 177 var factorsArr = factors.ToArray(); 178 var results = new List<Factor>(factors); 179 foreach (var f in factorsArr) { 180 if (f.ToString() == "1") results.Remove(f); 181 if (f.IsInverse) { 182 // find matching 183 Factor match; 184 if (f.IsSimpleFactor) match = factorsArr.FirstOrDefault(other => !other.IsInverse && f.Symbol.Equals(other.Symbol)); 185 else match = factorsArr.FirstOrDefault(other => !other.IsInverse && f.Expr.Equals(other.Expr)); 186 if (match != null) { 187 results.Remove(match); 188 results.Remove(f); 189 } 190 } 191 } 192 if (results.Count == 0) results.Add(new Factor('1')); 193 return results; 167 194 } 168 195 … … 170 197 // term can be merged (essentially an ordered list of factors) 171 198 internal class Term : IComparable<Term> { 172 private readonly SortedList<char, int> factorSymbs; // factor symbol and the number of occurrences 173 private readonly SortedList<Expr, int> invExpressions; 174 175 public IEnumerable<char> Symbols { 199 private readonly SortedList<Factor, int> factors; // factor symbol and the number of occurrences 200 201 public IEnumerable<Factor> Factors { 176 202 get { 177 return factorSymbs.SelectMany(p => Enumerable.Repeat(p.Key, p.Value)); 178 } 179 } 180 181 public IEnumerable<Expr> InvExpressions { 182 get { 183 if (invExpressions == null) return Enumerable.Empty<Expr>(); 184 return invExpressions.Where(p => p.Value > 0).SelectMany(p => Enumerable.Repeat(p.Key, p.Value)); 185 } 186 } 187 188 public Term(char f) { 189 factorSymbs = new SortedList<char, int>(new FactorComparer()); 190 factorSymbs.Add(f, 1); 191 } 192 public Term(IEnumerable<char> factors, IEnumerable<Expr> invFactors) { 193 factorSymbs = new SortedList<char, int>(new FactorComparer()); 194 invExpressions = new SortedList<Expr, int>(); 203 return factors.SelectMany(p => Enumerable.Repeat(p.Key, p.Value)); 204 } 205 } 206 207 public Term(Factor f) { 208 factors = new SortedList<Factor, int>(); 209 factors.Add(f, 1); 210 } 211 public Term(IEnumerable<Factor> factors) { 212 this.factors = new SortedList<Factor, int>(); 195 213 foreach (var f in factors) { 196 if (factorSymbs.ContainsKey(f)) factorSymbs[f] += 1; 197 else factorSymbs.Add(f, 1); 198 } 199 200 foreach (var invF in invFactors) { 201 if (invF.Terms.Count == 1) { 202 var t = invF.Terms.First(); 203 foreach (var f in factors.Concat(new char[] { '1' })) { 204 if (t.factorSymbs.ContainsKey(f)) { 205 t.factorSymbs[f] -= 1; 206 if (t.factorSymbs[f] == 0) t.factorSymbs.Remove(f); 207 } 208 } 209 } 210 if (invExpressions.ContainsKey(invF)) invExpressions[invF] += 1; 211 else invExpressions.Add(invF, 1); 214 if (this.factors.ContainsKey(f)) this.factors[f] += 1; 215 else this.factors.Add(f, 1); 212 216 } 213 217 } 214 218 215 219 public int CompareTo(Term other) { 216 if (ContainsNonTerminal( Symbols) && !ContainsNonTerminal(other.Symbols)) {220 if (ContainsNonTerminal(Factors) && !ContainsNonTerminal(other.Factors)) { 217 221 return 1; 218 } else if (!ContainsNonTerminal( Symbols) && ContainsNonTerminal(other.Symbols)) {222 } else if (!ContainsNonTerminal(Factors) && ContainsNonTerminal(other.Factors)) { 219 223 return -1; 220 224 } else { 221 var countComp = Symbols.Count().CompareTo(other.Symbols.Count());225 var countComp = Factors.Count().CompareTo(other.Factors.Count()); 222 226 if (countComp != 0) return countComp; 223 return string.Join("", Symbols).CompareTo(string.Join("", other.Symbols));227 return string.Join("", Factors).CompareTo(string.Join("", other.Factors)); 224 228 } 225 229 } 226 230 227 231 public override string ToString() { 228 if (InvExpressions.Any()) 229 return string.Join("*", Symbols) + "%" + string.Join("%", InvExpressions); 230 else { 231 return string.Join("*", Symbols); 232 } 232 233 return string.Join("*", Factors); 233 234 } 234 235 public override bool Equals(object obj) { 235 236 var other = obj as Term; 236 237 if (other == null) return false; 237 if (this.Symbols.Count() != other.Symbols.Count()) return false; 238 if (this.InvExpressions.Count() != other.InvExpressions.Count()) return false; 239 if (this.Symbols.Zip(other.Symbols, Tuple.Create).Any(t => t.Item1 != t.Item2)) return false; 240 if (this.InvExpressions.Zip(other.InvExpressions, Tuple.Create).Any(t => t.Item1 != t.Item2)) return false; 238 if (this.Factors.Count() != other.Factors.Count()) return false; 239 if (this.Factors.Zip(other.Factors, Tuple.Create).Any(t => t.Item1 != t.Item2)) return false; 241 240 return true; 242 241 } 243 242 public override int GetHashCode() { 244 243 var h = 31415; 245 foreach (var v in Symbols) {244 foreach (var v in Factors) { 246 245 h ^= v.GetHashCode(); 247 246 } 248 foreach (var v in InvExpressions) { 249 h ^= v.GetHashCode(); 250 } 247 return h; 248 } 249 } 250 #endregion 251 252 #region factor 253 // factors is either a single symbol or an inverted expression 254 internal class Factor : IComparable<Factor> { 255 public bool IsSimpleFactor { get { return Expr == null; } } 256 public char Symbol { get { return symbol; } } 257 public Expr Expr { get { return expr; } } 258 public bool IsInverse { get { return inv; } } 259 private readonly char symbol = '\0'; 260 private readonly Expr expr; 261 private bool inv; 262 263 public Factor(char f) { 264 this.symbol = f; 265 } 266 public Factor(Expr expr) { 267 this.expr = expr; 268 } 269 270 public void Invert() { 271 this.inv = !inv; 272 } 273 274 public int CompareTo(Factor other) { 275 // 1) single symbol factors first 276 // 2) expression factors by expression compare 277 var crit1 = ContainsNonTerminal(this).CompareTo(ContainsNonTerminal(other)); 278 if (crit1 != 0) return crit1; 279 280 var crit2 = this.IsInverse.CompareTo(other.IsInverse); 281 if (crit2 != 0) return crit2; 282 283 var crit3 = this.IsSimpleFactor.CompareTo(other.IsSimpleFactor); 284 if (crit3 != 0) return crit3; 285 286 // both are simple or expressions 287 if (IsSimpleFactor) return this.symbol.CompareTo(other.symbol); 288 else return this.Expr.CompareTo(other.Expr); 289 } 290 291 public override string ToString() { 292 var s = Expr == null ? symbol.ToString() : "(" + expr.ToString() + ")"; 293 if (IsInverse) { 294 return "1/" + s; 295 } else return s; 296 } 297 public override bool Equals(object obj) { 298 var other = obj as Factor; 299 if (other == null) return false; 300 if (IsInverse != other.IsInverse) return false; 301 if (this.symbol != other.symbol) return false; 302 if (this.Expr != other.Expr) return false; 303 return true; 304 } 305 public override int GetHashCode() { 306 var h = 31415; 307 h ^= symbol.GetHashCode(); 308 if (Expr != null) h ^= Expr.GetHashCode(); 251 309 return h; 252 310 } … … 258 316 internal class Expr : IComparable<Expr> { 259 317 public readonly SortedSet<Term> Terms; // only set for Kind == Expr 260 public bool Inverse;318 //public bool Inverse; 261 319 public Expr(Term t) { 262 320 Terms = new SortedSet<Term>(); … … 286 344 287 345 public override string ToString() { 288 if (Inverse && Terms.Count > 1)289 return "(" + string.Join("+", Terms) + ")";290 else if (Inverse && Terms.Count == 1) {291 return Terms.First().ToString().Replace("%", "#").Replace("*", "%").Replace("#", "*");292 } else293 346 // if (Inverse && Terms.Count > 1) 347 // return "(" + string.Join("+", Terms) + ")"; 348 // else if (Inverse && Terms.Count == 1) { 349 // return Terms.First().ToString().Replace("%", "#").Replace("*", "%").Replace("#", "*"); 350 // } else 351 return string.Join("+", Terms); 294 352 } 295 353 public override bool Equals(object obj) { 296 354 var other = obj as Expr; 297 355 if (other == null) return false; 298 if (this.Inverse != other.Inverse) return false;356 //if (this.Inverse != other.Inverse) return false; 299 357 if (this.Terms.Count() != other.Terms.Count()) return false; 300 358 return this.Terms.Intersect(other.Terms).Count() == this.Terms.Count; … … 308 366 return h; 309 367 } 310 311 public void Invert() {312 this.Inverse = !Inverse;313 }314 368 } 315 369 #endregion … … 317 371 return symb >= 'A' && symb <= 'Z'; 318 372 } 319 internal static bool ContainsNonTerminal(IEnumerable<char> symbs) { 320 return symbs.Any(IsNonTerminal); 321 } 373 internal static bool ContainsNonTerminal(IEnumerable<Factor> factors) { 374 return factors.Any(ContainsNonTerminal); 375 } 376 internal static bool ContainsNonTerminal(Factor f) { 377 if (f.Expr == null) return IsNonTerminal(f.Symbol); 378 else return ContainsNonTerminal(f.Expr); 379 } 380 381 private static bool ContainsNonTerminal(Expr expr) { 382 return expr.Terms.Any(ContainsNonTerminal); 383 } 384 385 private static bool ContainsNonTerminal(Term term) { 386 return ContainsNonTerminal(term.Factors); 387 } 388 389 390 /* 322 391 323 392 internal class FactorComparer : IComparer<char> { … … 333 402 } 334 403 } 335 } 404 }*/ 336 405 } 337 406 }
Note: See TracChangeset
for help on using the changeset viewer.