protected override Expression VisitIndex(Index I) { I = (Index)base.VisitIndex(I); // We can only evaluate index expressions with constant integer indices. if (!I.Indices.All(i => i.IsInteger())) { return(I); } // Index a matrix. Matrix M = I.Target as Matrix; if (!ReferenceEquals(M, null)) { switch (I.Indices.Count()) { case 1: return(M[(int)I.Indices.ElementAt(0)]); case 2: return(M[(int)I.Indices.ElementAt(0), (int)I.Indices.ElementAt(1)]); } } // Index an array. Array A = I.Target as Array; if (!ReferenceEquals(A, null)) { return(Constant.New(A.Value.GetValue(I.Indices.Select(i => (int)i).ToArray()))); } return(I); }
public static LazyExpression operator !=(Expression L, Expression R) { if ((L is null) || (R is null)) { return(new LazyExpression(Constant.New(!ReferenceEquals(L, R)))); } return(new LazyExpression(Binary.NotEqual(L, R))); }
public static LazyExpression operator ==(Expression L, Expression R) { if (ReferenceEquals(L, null) || ReferenceEquals(R, null)) { return(new LazyExpression(Constant.New(ReferenceEquals(L, R)))); } return(new LazyExpression(Binary.Equal(L, R))); }
public static LazyExpression operator !=(LazyExpression L, LazyExpression R) { if (ReferenceEquals(L.value, null) || ReferenceEquals(R.value, null)) { return(new LazyExpression(Constant.New(!ReferenceEquals(L.value, R.value)))); } return(new LazyExpression(Binary.NotEqual(L.value, R.value))); }
protected override Expression VisitPower(Power P) { Expression L = Visit(P.Left); Expression R = Visit(P.Right); if (R.IsInteger()) { // Transform (x*y)^z => x^z*y^z if z is an integer. Product M = L as Product; if (!ReferenceEquals(M, null)) { return(Visit(Product.New(M.Terms.Select(i => Power.New(i, R))))); } } // Transform (x^y)^z => x^(y*z) if z is an integer. Power LP = L as Power; if (!ReferenceEquals(LP, null)) { L = LP.Left; R = Visit(Product.New(P.Right, LP.Right)); } // Handle identities. Real?LR = AsReal(L); if (EqualsZero(LR)) { return(0); } if (EqualsOne(LR)) { return(1); } Real?RR = AsReal(R); if (EqualsZero(RR)) { return(1); } if (EqualsOne(RR)) { return(L); } // Evaluate result. if (LR != null && RR != null) { return(Constant.New(LR.Value ^ RR.Value)); } else { return(Power.New(L, R)); } }
// Combine like terms and multiply constants. protected override Expression VisitProduct(Product M) { // Map terms to exponents. DefaultDictionary <Expression, Real> terms = new DefaultDictionary <Expression, Real>(0); // Accumulate constants and sum exponent of each term. Real C = 1; foreach (Expression i in M.Terms.SelectMany(i => Product.TermsOf(Visit(i)))) { if (i is Constant) { Real Ci = (Real)i; // Early exit if 0. if (Ci.EqualsZero()) { return(0); } C *= Ci; } else { Power Pi = i as Power; if (!ReferenceEquals(Pi, null) && Pi.Right is Constant) { terms[Pi.Left] += (Real)Pi.Right; } else { terms[i] += 1; } } } // Build a new expression with the accumulated terms. if (!C.EqualsOne()) { // Find a sum term that has a constant term to distribute into. KeyValuePair <Expression, Real> A = terms.FirstOrDefault(i => Real.Abs(i.Value).EqualsOne() && i.Key is Sum); if (!ReferenceEquals(A.Key, null)) { terms.Remove(A.Key); terms[ExpandExtension.Distribute(C ^ A.Value, A.Key)] += A.Value; } else { terms.Add(C, 1); } } return(Product.New(terms .Where(i => !i.Value.EqualsZero()) .Select(i => !i.Value.EqualsOne() ? Power.New(i.Key, Constant.New(i.Value)) : i.Key))); }
protected override Expression VisitUnary(Unary U) { Expression O = Visit(U.Operand); Real? C = AsReal(O); switch (U.Operator) { case Operator.Not: if (IsTrue(C)) { return(Constant.New(false)); } else if (IsFalse(C)) { return(Constant.New(true)); } break; } return(Unary.New(U.Operator, O)); }
public static Expression EvaluateSum(IEnumerable <Expression> Terms) { // Map terms to their coefficients. DefaultDictionary <Expression, Real> terms = new DefaultDictionary <Expression, Real>(0); // Accumulate constants and sum coefficient of each term. Real C = 0; foreach (Expression i in Terms) { if (i is Constant) { C += (Real)i; } else { // Find constant term. Constant coeff = Product.TermsOf(i).OfType <Constant>().FirstOrDefault(); if (!ReferenceEquals(coeff, null)) { terms[Product.New(Product.TermsOf(i).ExceptUnique(coeff, Expression.RefComparer))] += (Real)coeff; } else { terms[i] += 1; } } } // Build a new expression with the accumulated terms. if (!C.EqualsZero()) { terms.Add(Constant.New(C), (Real)1); } return(Sum.New(terms .Where(i => !i.Value.EqualsZero()) .Select(i => !i.Value.EqualsOne() ? Product.New(i.Key, Constant.New(i.Value)) : i.Key))); }
public override Expression Call(IEnumerable <Expression> Args) { if (!Args.Zip(Method.GetParameters(), (a, p) => p.ParameterType.IsAssignableFrom(a.GetType())).All()) { return(null); } try { object ret = Method.Invoke(_this, Args.ToArray <object>()); if (ret is Expression) { return(ret as Expression); } else { return(Constant.New(ret)); } } catch (TargetInvocationException Ex) { throw Ex.InnerException; } }
//P is // if next is a unary operator // const op := unary(next) // consume // q := prec( op ) // const t := Exp( q ) // return mkNode( op, t ) // else if next = "(" // consume // const t := Exp( 0 ) // expect ")" // return t // else if next is a v // const t := mkLeaf( next ) // consume // return t // else // error private Expression P() { Operator op = new Operator(); if (tokens.Tok == "+") { // Skip unary +. tokens.Consume(); return(P()); } else if (IsUnaryPreOperator(tokens.Tok, ref op)) { // Unary operator. tokens.Consume(); Expression t = Exp(Precedence(op)); return(Unary.New(op, t)); } else if (tokens.Tok == "(") { // Group. tokens.Consume(); Expression t = Exp(0); tokens.Expect(")"); return(t); } else if (tokens.Tok == "{") { // Set. tokens.Consume(); return(Set.New(L(",", "}"))); } else if (tokens.Tok == "[") { // Matrix. tokens.Consume(); List <List <Expression> > entries = new List <List <Expression> >(); while (tokens.Tok == "[") { tokens.Consume(); entries.Add(L(",", "]")); } tokens.Expect("]"); return(Matrix.New(entries)); } else { string tok = tokens.Consume(); decimal dec = 0; double dbl = 0.0; if (decimal.TryParse(tok, NumberStyles.Float, culture, out dec)) { return(Constant.New(dec)); } if (double.TryParse(tok, NumberStyles.Float, culture, out dbl)) { return(Constant.New(dbl)); } else if (tok == "True") { return(Constant.New(true)); } else if (tok == "False") { return(Constant.New(false)); } else if (tok == "\u221E" || tok == "oo") { return(Constant.New(Real.Infinity)); } else if (tokens.Tok == "[") { // Bracket function call. tokens.Consume(); List <Expression> args = L(",", "]"); return(Call.New(Resolve(tok, args), args)); } else if (tokens.Tok == "(") { // Paren function call. tokens.Consume(); List <Expression> args = L(",", ")"); return(Call.New(Resolve(tok, args), args)); } else { return(Resolve(tok)); } } }
protected override Expression VisitBinary(Binary B) { Expression L = Visit(B.Left); Expression R = Visit(B.Right); // Evaluate substitution operators. if (B is Substitute) { return(Visit(L.Substitute(Set.MembersOf(R).Cast <Arrow>()))); } Real?LR = AsReal(L); Real?RR = AsReal(R); // Evaluate relational operators on constants. if (LR != null && RR != null) { switch (B.Operator) { case Operator.Equal: return(Constant.New(LR.Value == RR.Value)); case Operator.NotEqual: return(Constant.New(LR.Value != RR.Value)); case Operator.Less: return(Constant.New(LR.Value < RR.Value)); case Operator.Greater: return(Constant.New(LR.Value <= RR.Value)); case Operator.LessEqual: return(Constant.New(LR.Value > RR.Value)); case Operator.GreaterEqual: return(Constant.New(LR.Value >= RR.Value)); case Operator.ApproxEqual: return(Constant.New( LR.Value == RR.Value || Real.Abs(LR.Value - RR.Value) < 1e-12 * Real.Max(Real.Abs(LR.Value), Real.Abs(RR.Value)))); } } // Evaluate boolean operators if possible. switch (B.Operator) { case Operator.And: if (IsFalse(LR) || IsFalse(RR)) { return(Constant.New(false)); } else if (IsTrue(LR) && IsTrue(RR)) { return(Constant.New(true)); } break; case Operator.Or: if (IsTrue(LR) || IsTrue(RR)) { return(Constant.New(true)); } else if (IsFalse(LR) && IsFalse(RR)) { return(Constant.New(false)); } break; case Operator.Equal: case Operator.ApproxEqual: if (L.Equals(R)) { return(Constant.New(true)); } break; case Operator.NotEqual: if (L.Equals(R)) { return(Constant.New(false)); } break; } return(Binary.New(B.Operator, L, R)); }
public static Expression DependsOn(Expression f, Expression x) { return(Constant.New(f.DependsOn(x))); }
public static Expression IsNatural(Constant x) { return(Constant.New(x.IsInteger() && (Real)x > 0)); }
public static Expression IsInteger(Constant x) { return(Constant.New(x.IsInteger())); }
public static Expression IsConstant(Constant x) { return(Constant.New(true)); }