Changeset 4239 for trunk/sources/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SymbolicSimplifier.cs
- Timestamp:
- 08/17/10 08:19:31 (14 years ago)
- Location:
- trunk/sources/HeuristicLab.Problems.DataAnalysis
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/sources/HeuristicLab.Problems.DataAnalysis
-
Property
svn:mergeinfo
set to
/branches/DataAnalysis/HeuristicLab.Problems.DataAnalysis merged eligible
-
Property
svn:mergeinfo
set to
-
trunk/sources/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SymbolicSimplifier.cs
r4068 r4239 32 32 /// <summary> 33 33 /// Simplistic simplifier for arithmetic expressions 34 /// Rules:35 /// * Constants are always the last argument to any function36 /// * f(c1, c2) => c3 (constant expression folding)37 34 /// </summary> 38 35 public class SymbolicSimplifier { … … 85 82 } 86 83 84 85 #region symbol predicates 86 private bool IsDivision(SymbolicExpressionTreeNode original) { 87 return original.Symbol is Division; 88 } 89 90 private bool IsMultiplication(SymbolicExpressionTreeNode original) { 91 return original.Symbol is Multiplication; 92 } 93 94 private bool IsSubtraction(SymbolicExpressionTreeNode original) { 95 return original.Symbol is Subtraction; 96 } 97 98 private bool IsAddition(SymbolicExpressionTreeNode original) { 99 return original.Symbol is Addition; 100 } 101 102 private bool IsVariable(SymbolicExpressionTreeNode original) { 103 return original.Symbol is Variable; 104 } 105 106 private bool IsConstant(SymbolicExpressionTreeNode original) { 107 return original.Symbol is Constant; 108 } 109 110 private bool IsAverage(SymbolicExpressionTreeNode original) { 111 return original.Symbol is Average; 112 } 113 private bool IsLog(SymbolicExpressionTreeNode original) { 114 return original.Symbol is Logarithm; 115 } 116 private bool IsIfThenElse(SymbolicExpressionTreeNode original) { 117 return original.Symbol is IfThenElse; 118 } 119 #endregion 120 87 121 /// <summary> 88 122 /// Creates a new simplified tree … … 94 128 return (SymbolicExpressionTreeNode)original.Clone(); 95 129 } else if (IsAddition(original)) { 96 if (original.SubTrees.Count == 1) { 97 return GetSimplifiedTree(original.SubTrees[0]); 130 return SimplifyAddition(original); 131 } else if (IsSubtraction(original)) { 132 return SimplifySubtraction(original); 133 } else if (IsMultiplication(original)) { 134 return SimplifyMultiplication(original); 135 } else if (IsDivision(original)) { 136 return SimplifyDivision(original); 137 } else if (IsAverage(original)) { 138 return SimplifyAverage(original); 139 } else if (IsLog(original)) { 140 // TODO simplify logarithm 141 return SimplifyAny(original); 142 } else if (IsIfThenElse(original)) { 143 // TODO simplify conditionals 144 return SimplifyAny(original); 145 } else if (IsAverage(original)) { 146 return SimplifyAverage(original); 147 } else { 148 return SimplifyAny(original); 149 } 150 } 151 152 #region specific simplification routines 153 private SymbolicExpressionTreeNode SimplifyAny(SymbolicExpressionTreeNode original) { 154 // can't simplify this function but simplify all subtrees 155 List<SymbolicExpressionTreeNode> subTrees = new List<SymbolicExpressionTreeNode>(original.SubTrees); 156 while (original.SubTrees.Count > 0) original.RemoveSubTree(0); 157 var clone = (SymbolicExpressionTreeNode)original.Clone(); 158 List<SymbolicExpressionTreeNode> simplifiedSubTrees = new List<SymbolicExpressionTreeNode>(); 159 foreach (var subTree in subTrees) { 160 simplifiedSubTrees.Add(GetSimplifiedTree(subTree)); 161 original.AddSubTree(subTree); 162 } 163 foreach (var simplifiedSubtree in simplifiedSubTrees) { 164 clone.AddSubTree(simplifiedSubtree); 165 } 166 if (simplifiedSubTrees.TrueForAll(t => IsConstant(t))) { 167 SimplifyConstantExpression(clone); 168 } 169 return clone; 170 } 171 172 private SymbolicExpressionTreeNode SimplifyConstantExpression(SymbolicExpressionTreeNode original) { 173 // not yet implemented 174 return original; 175 } 176 177 private SymbolicExpressionTreeNode SimplifyAverage(SymbolicExpressionTreeNode original) { 178 if (original.SubTrees.Count == 1) { 179 return GetSimplifiedTree(original.SubTrees[0]); 180 } else { 181 // simplify expressions x0..xn 182 // make sum(x0..xn) / n 183 Trace.Assert(original.SubTrees.Count > 1); 184 var sum = original.SubTrees 185 .Select(x => GetSimplifiedTree(x)) 186 .Aggregate((a, b) => MakeSum(a, b)); 187 return MakeFraction(sum, MakeConstant(original.SubTrees.Count)); 188 } 189 } 190 191 private SymbolicExpressionTreeNode SimplifyDivision(SymbolicExpressionTreeNode original) { 192 if (original.SubTrees.Count == 1) { 193 return Invert(GetSimplifiedTree(original.SubTrees[0])); 194 } else { 195 // simplify expressions x0..xn 196 // make multiplication (x0 * 1/(x1 * x1 * .. * xn)) 197 Trace.Assert(original.SubTrees.Count > 1); 198 var simplifiedTrees = original.SubTrees.Select(x => GetSimplifiedTree(x)); 199 return 200 MakeProduct(simplifiedTrees.First(), Invert(simplifiedTrees.Skip(1).Aggregate((a, b) => MakeProduct(a, b)))); 201 } 202 } 203 204 private SymbolicExpressionTreeNode SimplifyMultiplication(SymbolicExpressionTreeNode original) { 205 if (original.SubTrees.Count == 1) { 206 return GetSimplifiedTree(original.SubTrees[0]); 207 } else { 208 Trace.Assert(original.SubTrees.Count > 1); 209 return original.SubTrees 210 .Select(x => GetSimplifiedTree(x)) 211 .Aggregate((a, b) => MakeProduct(a, b)); 212 } 213 } 214 215 private SymbolicExpressionTreeNode SimplifySubtraction(SymbolicExpressionTreeNode original) { 216 if (original.SubTrees.Count == 1) { 217 return Negate(GetSimplifiedTree(original.SubTrees[0])); 218 } else { 219 // simplify expressions x0..xn 220 // make addition (x0,-x1..-xn) 221 Trace.Assert(original.SubTrees.Count > 1); 222 var simplifiedTrees = original.SubTrees.Select(x => GetSimplifiedTree(x)); 223 return simplifiedTrees.Take(1) 224 .Concat(simplifiedTrees.Skip(1).Select(x => Negate(x))) 225 .Aggregate((a, b) => MakeSum(a, b)); 226 } 227 } 228 229 private SymbolicExpressionTreeNode SimplifyAddition(SymbolicExpressionTreeNode original) { 230 if (original.SubTrees.Count == 1) { 231 return GetSimplifiedTree(original.SubTrees[0]); 232 } else { 233 // simplify expression x0..xn 234 // make addition (x0..xn) 235 Trace.Assert(original.SubTrees.Count > 1); 236 return original.SubTrees 237 .Select(x => GetSimplifiedTree(x)) 238 .Aggregate((a, b) => MakeSum(a, b)); 239 } 240 } 241 #endregion 242 243 244 245 #region low level tree restructuring 246 // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree 247 248 private SymbolicExpressionTreeNode MakeFraction(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) { 249 if (IsConstant(a) && IsConstant(b)) { 250 // fold constants 251 return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value); 252 } if (IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0)) { 253 return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a))); 254 } else if (IsVariable(a) && IsConstant(b)) { 255 // merge constant values into variable weights 256 var constB = ((ConstantTreeNode)b).Value; 257 ((VariableTreeNode)a).Weight /= constB; 258 return a; 259 } else if (IsAddition(a) && IsConstant(b)) { 260 return a.SubTrees 261 .Select(x => MakeFraction(x, b)) 262 .Aggregate((c, d) => MakeSum(c, d)); 263 } else if (IsMultiplication(a) && IsConstant(b)) { 264 return MakeProduct(a, Invert(b)); 265 } else if (IsDivision(a) && IsConstant(b)) { 266 // (a1 / a2) / c => (a1 / (a2 * c)) 267 Trace.Assert(a.SubTrees.Count == 2); 268 return MakeFraction(a.SubTrees[0], MakeProduct(a.SubTrees[1], b)); 269 } else if (IsDivision(a) && IsDivision(b)) { 270 // (a1 / a2) / (b1 / b2) => 271 Trace.Assert(a.SubTrees.Count == 2); 272 Trace.Assert(b.SubTrees.Count == 2); 273 return MakeFraction(MakeProduct(a.SubTrees[0], b.SubTrees[1]), MakeProduct(a.SubTrees[1], b.SubTrees[0])); 274 } else if (IsDivision(a)) { 275 // (a1 / a2) / b => (a1 / (a2 * b)) 276 Trace.Assert(a.SubTrees.Count == 2); 277 return MakeFraction(a.SubTrees[0], MakeProduct(a.SubTrees[1], b)); 278 } else if (IsDivision(b)) { 279 // a / (b1 / b2) => (a * b2) / b1 280 Trace.Assert(b.SubTrees.Count == 2); 281 return MakeFraction(MakeProduct(a, b.SubTrees[1]), b.SubTrees[0]); 282 } else { 283 var div = divSymbol.CreateTreeNode(); 284 div.AddSubTree(a); 285 div.AddSubTree(b); 286 return div; 287 } 288 } 289 290 private SymbolicExpressionTreeNode MakeSum(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) { 291 if (IsConstant(a) && IsConstant(b)) { 292 // fold constants 293 ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value; 294 return a; 295 } else if (IsConstant(a)) { 296 // c + x => x + c 297 // b is not constant => make sure constant is on the right 298 return MakeSum(b, a); 299 } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) { 300 // x + 0 => x 301 return a; 302 } else if (IsAddition(a) && IsAddition(b)) { 303 // merge additions 304 var add = addSymbol.CreateTreeNode(); 305 for (int i = 0; i < a.SubTrees.Count - 1; i++) add.AddSubTree(a.SubTrees[i]); 306 for (int i = 0; i < b.SubTrees.Count - 1; i++) add.AddSubTree(b.SubTrees[i]); 307 if (IsConstant(a.SubTrees.Last()) && IsConstant(b.SubTrees.Last())) { 308 add.AddSubTree(MakeSum(a.SubTrees.Last(), b.SubTrees.Last())); 309 } else if (IsConstant(a.SubTrees.Last())) { 310 add.AddSubTree(b.SubTrees.Last()); 311 add.AddSubTree(a.SubTrees.Last()); 98 312 } else { 99 // simplify expression x0..xn 100 // make addition (x0..xn) 101 Trace.Assert(original.SubTrees.Count > 1); 102 return original.SubTrees 103 .Select(x => GetSimplifiedTree(x)) 104 .Aggregate((a, b) => MakeAddition(a, b)); 105 } 106 } else if (IsSubtraction(original)) { 107 if (original.SubTrees.Count == 1) { 108 return Negate(GetSimplifiedTree(original.SubTrees[0])); 313 add.AddSubTree(a.SubTrees.Last()); 314 add.AddSubTree(b.SubTrees.Last()); 315 } 316 MergeVariablesInSum(add); 317 return add; 318 } else if (IsAddition(b)) { 319 return MakeSum(b, a); 320 } else if (IsAddition(a) && IsConstant(b)) { 321 // a is an addition and b is a constant => append b to a and make sure the constants are merged 322 var add = addSymbol.CreateTreeNode(); 323 for (int i = 0; i < a.SubTrees.Count - 1; i++) add.AddSubTree(a.SubTrees[i]); 324 if (IsConstant(a.SubTrees.Last())) 325 add.AddSubTree(MakeSum(a.SubTrees.Last(), b)); 326 else { 327 add.AddSubTree(a.SubTrees.Last()); 328 add.AddSubTree(b); 329 } 330 return add; 331 } else if (IsAddition(a)) { 332 // a is already an addition => append b 333 var add = addSymbol.CreateTreeNode(); 334 add.AddSubTree(b); 335 foreach (var subTree in a.SubTrees) { 336 add.AddSubTree(subTree); 337 } 338 MergeVariablesInSum(add); 339 return add; 340 } else { 341 var add = addSymbol.CreateTreeNode(); 342 add.AddSubTree(a); 343 add.AddSubTree(b); 344 MergeVariablesInSum(add); 345 return add; 346 } 347 } 348 349 // makes sure variable symbols in sums are combined 350 // possible improvment: combine sums of products where the products only reference the same variable 351 private void MergeVariablesInSum(SymbolicExpressionTreeNode sum) { 352 var subtrees = new List<SymbolicExpressionTreeNode>(sum.SubTrees); 353 while (sum.SubTrees.Count > 0) sum.RemoveSubTree(0); 354 var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>() 355 group node by node.VariableName into g 356 select g; 357 var unchangedSubTrees = subtrees.Where(t => !(t is VariableTreeNode)); 358 359 foreach (var variableNodeGroup in groupedVarNodes) { 360 var weightSum = variableNodeGroup.Select(t => t.Weight).Sum(); 361 var representative = variableNodeGroup.First(); 362 representative.Weight = weightSum; 363 sum.AddSubTree(representative); 364 } 365 foreach (var unchangedSubtree in unchangedSubTrees) 366 sum.AddSubTree(unchangedSubtree); 367 } 368 369 370 private SymbolicExpressionTreeNode MakeProduct(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) { 371 if (IsConstant(a) && IsConstant(b)) { 372 // fold constants 373 ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value; 374 return a; 375 } else if (IsConstant(a)) { 376 // a * $ => $ * a 377 return MakeProduct(b, a); 378 } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) { 379 // $ * 1.0 => $ 380 return a; 381 } else if (IsConstant(b) && IsVariable(a)) { 382 // multiply constants into variables weights 383 ((VariableTreeNode)a).Weight *= ((ConstantTreeNode)b).Value; 384 return a; 385 } else if (IsConstant(b) && IsAddition(a)) { 386 // multiply constants into additions 387 return a.SubTrees.Select(x => MakeProduct(x, b)).Aggregate((c, d) => MakeSum(c, d)); 388 } else if (IsDivision(a) && IsDivision(b)) { 389 // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2) 390 Trace.Assert(a.SubTrees.Count == 2); 391 Trace.Assert(b.SubTrees.Count == 2); 392 return MakeFraction(MakeProduct(a.SubTrees[0], b.SubTrees[0]), MakeProduct(a.SubTrees[1], b.SubTrees[1])); 393 } else if (IsDivision(a)) { 394 // (a1 / a2) * b => (a1 * b) / a2 395 Trace.Assert(a.SubTrees.Count == 2); 396 return MakeFraction(MakeProduct(a.SubTrees[0], b), a.SubTrees[1]); 397 } else if (IsDivision(b)) { 398 // a * (b1 / b2) => (b1 * a) / b2 399 Trace.Assert(b.SubTrees.Count == 2); 400 return MakeFraction(MakeProduct(b.SubTrees[0], a), b.SubTrees[1]); 401 } else if (IsMultiplication(a) && IsMultiplication(b)) { 402 // merge multiplications (make sure constants are merged) 403 var mul = mulSymbol.CreateTreeNode(); 404 for (int i = 0; i < a.SubTrees.Count; i++) mul.AddSubTree(a.SubTrees[i]); 405 for (int i = 0; i < b.SubTrees.Count; i++) mul.AddSubTree(b.SubTrees[i]); 406 MergeVariablesAndConstantsInProduct(mul); 407 return mul; 408 } else if (IsMultiplication(b)) { 409 return MakeProduct(b, a); 410 } else if (IsMultiplication(a)) { 411 // a is already an multiplication => append b 412 a.AddSubTree(b); 413 MergeVariablesAndConstantsInProduct(a); 414 return a; 415 } else { 416 var mul = mulSymbol.CreateTreeNode(); 417 mul.SubTrees.Add(a); 418 mul.SubTrees.Add(b); 419 MergeVariablesAndConstantsInProduct(mul); 420 return mul; 421 } 422 } 423 #endregion 424 425 // helper to combine the constant factors in products and to combine variables (powers of 2, 3...) 426 private void MergeVariablesAndConstantsInProduct(SymbolicExpressionTreeNode prod) { 427 var subtrees = new List<SymbolicExpressionTreeNode>(prod.SubTrees); 428 while (prod.SubTrees.Count > 0) prod.RemoveSubTree(0); 429 var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>() 430 group node by node.VariableName into g 431 orderby g.Count() 432 select g; 433 var constantProduct = (from node in subtrees.OfType<VariableTreeNode>() 434 select node.Weight) 435 .Concat(from node in subtrees.OfType<ConstantTreeNode>() 436 select node.Value) 437 .DefaultIfEmpty(1.0) 438 .Aggregate((c1, c2) => c1 * c2); 439 440 var unchangedSubTrees = from tree in subtrees 441 where !(tree is VariableTreeNode) 442 where !(tree is ConstantTreeNode) 443 select tree; 444 445 foreach (var variableNodeGroup in groupedVarNodes) { 446 var representative = variableNodeGroup.First(); 447 representative.Weight = 1.0; 448 if (variableNodeGroup.Count() > 1) { 449 var poly = mulSymbol.CreateTreeNode(); 450 for (int p = 0; p < variableNodeGroup.Count(); p++) { 451 poly.AddSubTree((SymbolicExpressionTreeNode)representative.Clone()); 452 } 453 prod.AddSubTree(poly); 109 454 } else { 110 // simplify expressions x0..xn 111 // make addition (x0,-x1..-xn) 112 Trace.Assert(original.SubTrees.Count > 1); 113 var simplifiedTrees = original.SubTrees.Select(x => GetSimplifiedTree(x)); 114 return simplifiedTrees.Take(1) 115 .Concat(simplifiedTrees.Skip(1).Select(x => Negate(x))) 116 .Aggregate((a, b) => MakeAddition(a, b)); 117 } 118 } else if (IsMultiplication(original)) { 119 if (original.SubTrees.Count == 1) { 120 return GetSimplifiedTree(original.SubTrees[0]); 121 } else { 122 Trace.Assert(original.SubTrees.Count > 1); 123 return original.SubTrees 124 .Select(x => GetSimplifiedTree(x)) 125 .Aggregate((a, b) => MakeMultiplication(a, b)); 126 } 127 } else if (IsDivision(original)) { 128 if (original.SubTrees.Count == 1) { 129 return Invert(GetSimplifiedTree(original.SubTrees[0])); 130 } else { 131 // simplify expressions x0..xn 132 // make multiplication (x0 * 1/(x1 * x1 * .. * xn)) 133 Trace.Assert(original.SubTrees.Count > 1); 134 var simplifiedTrees = original.SubTrees.Select(x => GetSimplifiedTree(x)); 135 return 136 MakeMultiplication(simplifiedTrees.First(), Invert(simplifiedTrees.Skip(1).Aggregate((a, b) => MakeMultiplication(a, b)))); 137 } 138 } else if (IsAverage(original)) { 139 if (original.SubTrees.Count == 1) { 140 return GetSimplifiedTree(original.SubTrees[0]); 141 } else { 142 // simpliy expressions x0..xn 143 // make sum(x0..xn) / n 144 Trace.Assert(original.SubTrees.Count > 1); 145 var sum = original.SubTrees 146 .Select(x => GetSimplifiedTree(x)) 147 .Aggregate((a, b) => MakeAddition(a, b)); 148 return MakeDivision(sum, MakeConstant(original.SubTrees.Count)); 149 } 150 } else { 151 // can't simplify this function but simplify all subtrees 152 // TODO evaluate the function if original is a constant expression 153 List<SymbolicExpressionTreeNode> subTrees = new List<SymbolicExpressionTreeNode>(original.SubTrees); 154 while (original.SubTrees.Count > 0) original.RemoveSubTree(0); 155 var clone = (SymbolicExpressionTreeNode)original.Clone(); 156 foreach (var subTree in subTrees) { 157 clone.AddSubTree(GetSimplifiedTree(subTree)); 158 original.AddSubTree(subTree); 159 } 160 return clone; 161 } 162 } 163 455 prod.AddSubTree(representative); 456 } 457 } 458 459 foreach (var unchangedSubtree in unchangedSubTrees) 460 prod.AddSubTree(unchangedSubtree); 461 462 if (!constantProduct.IsAlmost(1.0)) { 463 prod.AddSubTree(MakeConstant(constantProduct)); 464 } 465 } 466 467 468 #region helper functions 164 469 /// <summary> 165 470 /// x => x * -1 … … 184 489 } else { 185 490 // any other function 186 return Make Multiplication(x, MakeConstant(-1));491 return MakeProduct(x, MakeConstant(-1)); 187 492 } 188 493 return x; … … 197 502 private SymbolicExpressionTreeNode Invert(SymbolicExpressionTreeNode x) { 198 503 if (IsConstant(x)) { 199 ((ConstantTreeNode)x).Value = 1.0 / ((ConstantTreeNode)x).Value; 504 return MakeConstant(1.0 / ((ConstantTreeNode)x).Value); 505 } else if (IsDivision(x)) { 506 Trace.Assert(x.SubTrees.Count == 2); 507 return MakeFraction(x.SubTrees[1], x.SubTrees[0]); 200 508 } else { 201 509 // any other function 202 return MakeDivision(MakeConstant(1), x); 203 } 204 return x; 205 } 206 207 private SymbolicExpressionTreeNode MakeDivision(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) { 208 if (IsConstant(a) && IsConstant(b)) { 209 return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value); 210 } else if (IsVariable(a) && IsConstant(b)) { 211 var constB = ((ConstantTreeNode)b).Value; 212 ((VariableTreeNode)a).Weight /= constB; 213 return a; 214 } else { 215 var div = divSymbol.CreateTreeNode(); 216 div.AddSubTree(a); 217 div.AddSubTree(b); 218 return div; 219 } 220 } 221 222 private SymbolicExpressionTreeNode MakeAddition(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) { 223 if (IsConstant(a) && IsConstant(b)) { 224 // merge constants 225 ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value; 226 return a; 227 } else if (IsConstant(a)) { 228 // c + x => x + c 229 // b is not constant => make sure constant is on the right 230 return MakeAddition(b, a); 231 } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) { 232 // x + 0 => x 233 return a; 234 } else if (IsAddition(a) && IsAddition(b)) { 235 // merge additions 236 var add = addSymbol.CreateTreeNode(); 237 for (int i = 0; i < a.SubTrees.Count - 1; i++) add.AddSubTree(a.SubTrees[i]); 238 for (int i = 0; i < b.SubTrees.Count - 1; i++) add.AddSubTree(b.SubTrees[i]); 239 if (IsConstant(a.SubTrees.Last()) && IsConstant(b.SubTrees.Last())) { 240 add.AddSubTree(MakeAddition(a.SubTrees.Last(), b.SubTrees.Last())); 241 } else if (IsConstant(a.SubTrees.Last())) { 242 add.AddSubTree(b.SubTrees.Last()); 243 add.AddSubTree(a.SubTrees.Last()); 244 } else { 245 add.AddSubTree(a.SubTrees.Last()); 246 add.AddSubTree(b.SubTrees.Last()); 247 } 248 MergeVariables(add); 249 return add; 250 } else if (IsAddition(b)) { 251 return MakeAddition(b, a); 252 } else if (IsAddition(a) && IsConstant(b)) { 253 var add = addSymbol.CreateTreeNode(); 254 for (int i = 0; i < a.SubTrees.Count - 1; i++) add.AddSubTree(a.SubTrees[i]); 255 if (IsConstant(a.SubTrees.Last())) 256 add.AddSubTree(MakeAddition(a.SubTrees.Last(), b)); 257 else { 258 add.AddSubTree(a.SubTrees.Last()); 259 add.AddSubTree(b); 260 } 261 return add; 262 } else if (IsAddition(a)) { 263 var add = addSymbol.CreateTreeNode(); 264 add.AddSubTree(b); 265 foreach (var subTree in a.SubTrees) { 266 add.AddSubTree(subTree); 267 } 268 MergeVariables(add); 269 return add; 270 } else { 271 var add = addSymbol.CreateTreeNode(); 272 add.AddSubTree(a); 273 add.AddSubTree(b); 274 MergeVariables(add); 275 return add; 276 } 277 } 278 279 private void MergeVariables(SymbolicExpressionTreeNode add) { 280 var subtrees = new List<SymbolicExpressionTreeNode>(add.SubTrees); 281 while (add.SubTrees.Count > 0) add.RemoveSubTree(0); 282 var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>() 283 group node by node.VariableName into g 284 select g; 285 var unchangedSubTrees = subtrees.Where(t => !(t is VariableTreeNode)); 286 287 foreach (var variableNodeGroup in groupedVarNodes) { 288 var weightSum = variableNodeGroup.Select(t => t.Weight).Sum(); 289 var representative = variableNodeGroup.First(); 290 representative.Weight = weightSum; 291 add.AddSubTree(representative); 292 } 293 foreach (var unchangedSubtree in unchangedSubTrees) 294 add.AddSubTree(unchangedSubtree); 295 } 296 297 private SymbolicExpressionTreeNode MakeMultiplication(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) { 298 if (IsConstant(a) && IsConstant(b)) { 299 ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value; 300 return a; 301 } else if (IsConstant(a)) { 302 return MakeMultiplication(b, a); 303 } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) { 304 return a; 305 } else if (IsConstant(b) && IsVariable(a)) { 306 ((VariableTreeNode)a).Weight *= ((ConstantTreeNode)b).Value; 307 return a; 308 } else if (IsConstant(b) && IsAddition(a)) { 309 return a.SubTrees.Select(x => MakeMultiplication(x, b)).Aggregate((c, d) => MakeAddition(c, d)); 310 } else if (IsDivision(a) && IsDivision(b)) { 311 return MakeDivision(MakeMultiplication(a.SubTrees[0], b.SubTrees[0]), MakeMultiplication(a.SubTrees[1], b.SubTrees[1])); 312 } else if (IsDivision(a)) { 313 Trace.Assert(a.SubTrees.Count == 2); 314 return MakeDivision(MakeMultiplication(a.SubTrees[0], b), a.SubTrees[1]); 315 } else if (IsDivision(b)) { 316 Trace.Assert(b.SubTrees.Count == 2); 317 return MakeDivision(MakeMultiplication(b.SubTrees[0], a), b.SubTrees[1]); 318 } else if (IsMultiplication(a) && IsMultiplication(b)) { 319 var mul = mulSymbol.CreateTreeNode(); 320 for (int i = 0; i < a.SubTrees.Count - 1; i++) mul.AddSubTree(a.SubTrees[i]); 321 for (int i = 0; i < b.SubTrees.Count - 1; i++) mul.AddSubTree(b.SubTrees[i]); 322 mul.AddSubTree(MakeMultiplication(a.SubTrees.Last(), b.SubTrees.Last())); 323 return mul; 324 } else if (IsMultiplication(a)) { 325 var mul = mulSymbol.CreateTreeNode(); 326 for (int i = 0; i < a.SubTrees.Count - 1; i++) mul.AddSubTree(a.SubTrees[i]); 327 mul.AddSubTree(MakeMultiplication(a.SubTrees.Last(), b)); 328 return mul; 329 } else if (IsMultiplication(b)) { 330 var mul = mulSymbol.CreateTreeNode(); 331 for (int i = 0; i < b.SubTrees.Count - 1; i++) mul.AddSubTree(b.SubTrees[i]); 332 mul.AddSubTree(MakeMultiplication(b.SubTrees.Last(), a)); 333 return mul; 334 } else { 335 var mul = mulSymbol.CreateTreeNode(); 336 mul.SubTrees.Add(a); 337 mul.SubTrees.Add(b); 338 return mul; 339 } 340 } 341 342 #region is symbol ? 343 private bool IsDivision(SymbolicExpressionTreeNode original) { 344 return original.Symbol is Division; 345 } 346 347 private bool IsMultiplication(SymbolicExpressionTreeNode original) { 348 return original.Symbol is Multiplication; 349 } 350 351 private bool IsSubtraction(SymbolicExpressionTreeNode original) { 352 return original.Symbol is Subtraction; 353 } 354 355 private bool IsAddition(SymbolicExpressionTreeNode original) { 356 return original.Symbol is Addition; 357 } 358 359 private bool IsVariable(SymbolicExpressionTreeNode original) { 360 return original.Symbol is Variable; 361 } 362 363 private bool IsConstant(SymbolicExpressionTreeNode original) { 364 return original.Symbol is Constant; 365 } 366 367 private bool IsAverage(SymbolicExpressionTreeNode original) { 368 return original.Symbol is Average; 369 } 370 #endregion 510 return MakeFraction(MakeConstant(1), x); 511 } 512 } 371 513 372 514 private SymbolicExpressionTreeNode MakeConstant(double value) { … … 382 524 return tree; 383 525 } 526 #endregion 384 527 } 385 528 }
Note: See TracChangeset
for help on using the changeset viewer.