private Expr _Substitute(NullExpr e) { return e; }
public override Null Visit(NullExpr node) { context = null; node.computedType = new NullType(); return null; }
private Expr _Numericize(NullExpr e) { return e; }
private Expr _Numericize(CompositeExpr e) { Expr[] args = new Expr[e.Args.Length]; for (int i = 0; i < e.Args.Length; i++) if ((i != 0 || head(e) != WKSID.index) && !(i == 0 && e.Head == WellKnownSym.summation && e.Args.Length > 1)) args[i] = Numericize(e.Args[i]); else args[i] = e.Args[i]; Expr val = Ag(e, 0); if (e.Head is WellKnownSym) { DoubleNumber dn1 = null; DoubleNumber dn2 = null; IntegerNumber in1 = null; IntegerNumber in2 = null; ComplexNumber cn1 = null; ComplexNumber cn2 = null; if (args.Length > 0) { dn1 = args[0] as DoubleNumber; cn1 = args[0] as ComplexNumber; in1 = args[0] as IntegerNumber; } if (args.Length > 1) { dn2 = args[1] as DoubleNumber; cn2 = args[1] as ComplexNumber; in2 = args[1] as IntegerNumber; } double d1 = 0; double d2 = 0; if (in2 != null) d2 = (double)in2.Num; if (in1 != null) d1 = (double)in1.Num; if (dn2 != null) d2 = dn2.Num; if (dn1 != null) d1 = dn1.Num; bool num1 = dn1 != null || in1 != null; bool num2 = dn2 != null || in2 != null; WKSID id = ((WellKnownSym)e.Head).ID; switch (id) { case WKSID.im: Trace.Assert(args.Length == 1); if (args[0] is RealNumber) return 0.0; else if (args[0] is ComplexNumber) return ((ComplexNumber)args[0]).Im; break; case WKSID.magnitude: if (in1 != null) return in1.Num.abs(); if (dn1 != null) return Math.Abs(dn1.Num); if (cn1 != null) return Numericize(new CompositeExpr(WellKnownSym.root, 2, new CompositeExpr(WellKnownSym.plus, new CompositeExpr(WellKnownSym.power, cn1.Re, 2), new CompositeExpr(WellKnownSym.power, cn1.Im, 2)))); break; case WKSID.minus: Trace.Assert(args.Length == 1); if (num1) if (in1 != null) return new IntegerNumber(-in1.Num); else return -d1; else if (args[0] is ComplexNumber) return NMinus((ComplexNumber)args[0]); else if (args[0] is ArrayExpr) { ArrayExpr ae = new ArrayExpr((Array)((ArrayExpr)args[0]).Elts.Clone()); foreach (int[] i in ae.Indices) ae[i] = Numericize(Minus(ae[i])); if (!args[0].Annotations.Contains("Force Parentheses") || !args[0].Annotations["Force Parentheses"].Equals(0)) ae.Annotations["Force Parentheses"] = 1; return ae; } break; case WKSID.plus: { Trace.Assert(args.Length > 0); if (args.Length == 1) { return args[0]; } if (Array.TrueForAll(args, delegate(Expr a) { return a is ArrayExpr; })) { ArrayExpr[] aes = Array.ConvertAll<Expr, ArrayExpr>(args, delegate(Expr a) { return (ArrayExpr)a; }); int[] dims = aes[0].Dims; bool isok = true; for (int i = 1; isok && i < args.Length; i++) { int[] dd = aes[i].Dims; if (dd.Length != dims.Length) isok = false; for (int j = 0; isok && j < dims.Length; j++) if (dims[j] != dd[j]) isok = false; } if (isok) { ArrayExpr newae = new ArrayExpr((Array)aes[0].Elts.Clone()); foreach (int[] ix in newae.Indices) { newae[ix] = Numericize(Plus(Array.ConvertAll<ArrayExpr, Expr>(aes, delegate(ArrayExpr ae) { return ae[ix]; }))); } newae.Annotations["Force Parentheses"] = 1; return newae; } } List<Expr> leftover = new List<Expr>(); double rsum = 0; double isum = 0; IntegerNumber risum = 0; bool anyd = false, anyc = false, anyi = false; foreach (Expr p in args) { DoubleNumber dn = p as DoubleNumber; IntegerNumber inn = p as IntegerNumber; ComplexNumber cn = p as ComplexNumber; if (dn != null) { if (anyi) { rsum = dn.Num + (double)risum.Num; anyi = false; } else rsum += dn.Num; anyd = true; } else if (inn != null) { if (anyd) rsum += (double)inn.Num; else { risum = risum.Num + inn.Num; anyi = true; } } else if (cn != null) { DoubleNumber red = cn.Re as DoubleNumber; DoubleNumber imd = cn.Im as DoubleNumber; if (red != null && imd != null) { if (anyi) rsum = red.Num + (double)risum.Num; else rsum += red.Num; isum += imd.Num; anyd = true; anyc = true; anyi = false; } else leftover.Add(p); } else leftover.Add(p); } Number rn = anyd ? (Number)new DoubleNumber(rsum) : (Number)risum; Number n = anyc ? (Number)new ComplexNumber(rsum, isum) : (Number)rn; if (leftover.Count == 0) return n; else { if (anyd || anyi || anyc) leftover.Add(n); return new CompositeExpr(e.Head, leftover.ToArray()); } } case WKSID.mod: if (args.Length != 2) break; if (in1 != null && in2 != null) return new IntegerNumber(in1.Num % in2.Num); else if (in1 != null && dn2 != null) return Math.IEEERemainder(in1.Num.AsDouble(), dn2.Num); else if (dn1 != null && in2 != null) return Math.IEEERemainder(dn1.Num, in2.Num.AsDouble()); else if (dn1 != null && dn2 != null) return Math.IEEERemainder(dn1.Num, dn2.Num); break; case WKSID.power: if (args.Length < 2) break; Trace.Assert(args.Length == 2); if (num1 && (d1 >= 0 || in2 != null) && num2) { double pow = Math.Pow(d1, d2); return in1 != null && in2 != null && d2 > 0 ? (Expr)new IntegerNumber((int)pow) : (Expr)new DoubleNumber(pow); } else { if (num1) cn1 = new ComplexNumber(d1, 0.0); if (num2) cn2 = new ComplexNumber(d2, 0.0); if (cn1 != null && cn2 != null) return NPower(cn1, cn2); } if (num2 && d2 == 0) return new DoubleNumber(1); if (num2 && d2 == 1) return args[0]; if (args[0] is ArrayExpr && args[1] == new LetterSym('T')) { // matrix transpose // FIXME: actually, this should probably be turned into a wellknownsym "transpose" by parse2. Issue there is how to know T isn't being // used as a variable? ArrayExpr ae = (ArrayExpr)args[0]; if (ae.Elts.Rank == 1) { Expr[,] n = new Expr[ae.Elts.Length, 1]; for (int i = 0; i < ae.Elts.Length; i++) { n[i, 0] = ae[i]; } ae = new ArrayExpr(n); ae.Annotations["Force Parentheses"] = 1; } else if (ae.Elts.Rank == 2) { int h = ae.Elts.GetLength(0); int w = ae.Elts.GetLength(1); Expr[,] n = new Expr[w, h]; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { n[j, i] = ae[i, j]; } } ae = new ArrayExpr(n); ae.Annotations["Force Parentheses"] = 1; return ae; } } break; case WKSID.re: Trace.Assert(args.Length == 1); if (num1) return args[0]; else if (cn1 != null) return cn1.Re; break; case WKSID.times: Trace.Assert(args.Length > 0); if (args.Length == 1) { return args[0]; } else { List<Expr> leftover = new List<Expr>(); int start = 0; while (start < args.Length) { int end; bool isarray = args[start] is ArrayExpr; for (end = start + 1; end < args.Length; end++) { if (isarray != (args[end] is ArrayExpr)) break; } leftover.AddRange(isarray ? NMultiplyArrays(args, start, end) : NMultiplyScalars(args, start, end)); start = end; } if (leftover.Count == 1) { return leftover[0]; } else { leftover = this.NMultipyAll(args, e); if (leftover.Count == 1) return leftover[0]; else return new CompositeExpr(e.Head, leftover.ToArray()); } //original code before matrix scalar computations //if(leftover.Count == 1) return leftover[0]; //else //return new CompositeExpr(e.Head, leftover.ToArray()); } case WKSID.divide: Trace.Assert(args.Length == 1); if (num1) return 1 / d1; else if (args[0] is ComplexNumber) return NReciprocal((ComplexNumber)args[0]); break; case WKSID.ln: Trace.Assert(args.Length == 1); if (num1) { if (d1 >= 0) return Math.Log(d1); return NLog(d1); } else if (args[0] is ComplexNumber) return NLog((ComplexNumber)args[0]); break; case WKSID.log: /* log takes base then value to take the logarithm of */ if (args.Length == 1) { dn2 = dn1; in2 = in1; cn2 = cn1; d2 = d1; num2 = num1; d1 = 10; dn1 = 10; in1 = null; cn1 = null; num1 = true; } if (num1 && num2) { if (d1 >= 0 && num2 && d2 >= 0) return Math.Log(d2, d1); else return double.NaN; } else { if (num1) cn1 = new ComplexNumber(d1, 0.0); if (num2) cn2 = new ComplexNumber(d2, 0.0); if (cn1 != null && cn2 != null) return NTimes(NLog(cn2), NReciprocal(NLog(cn1))); } break; case WKSID.root: /* takes root number (eg 2 for square root), value to take the root of */ Trace.Assert(args.Length == 2); if (num1 && num2 && d2 >= 0) return Math.Pow(d2, 1 / d1); else { if (num1) cn1 = new ComplexNumber(d1, 0.0); if (num2) cn2 = new ComplexNumber(d2, 0.0); if (cn1 != null && cn2 != null) return NPower(cn2, NReciprocal(cn1)); } if (head(args[1]) == WKSID.power) return Numericize(Power(Ag(args[1], 0), Mult(Ag(args[1], 1), Divide(args[0])))); break; case WKSID.index: { bool didnumericize = false; if (!(args[0] is ArrayExpr)) { args[0] = Numericize(args[0]); didnumericize = true; } ArrayExpr aex = null, aix = null; if (!IsArrayIndex(e, ref aex, ref aix)) { if (!didnumericize) args[0] = Numericize(args[0]); break; } int[] ix = ConvertToInd(aix, ExprToInd); if (ix == null) { if (!didnumericize) args[0] = Numericize(args[0]); break; } return Numericize(aex[ix]); } case WKSID.sin: Trace.Assert(args.Length == 1); if (head(val) == WKSID.times && Ag(val, 1) == _degree) return Numericize(new CompositeExpr(WellKnownSym.sin, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180)))))); if (num1) return Math.Sin(d1); else if (cn1 != null) return NSin(cn1); break; case WKSID.cos: Trace.Assert(args.Length == 1); if (head(val) == WKSID.times && Ag(val, 1) == _degree) return Numericize(new CompositeExpr(WellKnownSym.cos, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180)))))); if (num1) return Math.Cos(d1); else if (cn1 != null) return NCos(cn1); break; case WKSID.tan: Trace.Assert(args.Length == 1); if (head(val) == WKSID.times && Ag(val, 1) == _degree) return Numericize(new CompositeExpr(WellKnownSym.tan, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180)))))); if (num1) return Math.Tan(d1); else if (cn1 != null) return NTan(cn1); break; case WKSID.sec: Trace.Assert(args.Length == 1); if (head(val) == WKSID.times && Ag(val, 1) == _degree) return Numericize(new CompositeExpr(WellKnownSym.sec, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180)))))); if (num1) return 1 / Math.Cos(d1); else if (cn1 != null) return NReciprocal(NCos(cn1)); break; case WKSID.csc: Trace.Assert(args.Length == 1); if (head(val) == WKSID.times && Ag(val, 1) == _degree) return Numericize(new CompositeExpr(WellKnownSym.csc, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180)))))); if (num1) return 1 / Math.Sin(d1); else if (args[0] is ComplexNumber) return NReciprocal(NSin(cn1)); break; case WKSID.cot: Trace.Assert(args.Length == 1); if (head(val) == WKSID.times && Ag(val, 1) == _degree) return Numericize(new CompositeExpr(WellKnownSym.cot, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180)))))); if (num1) return 1 / Math.Tan(d1); if (cn1 != null) return NReciprocal(NTan(cn1)); break; case WKSID.asin: Trace.Assert(args.Length == 1); if (num1) return Math.Asin(d1); if (cn1 != null) return NArcSin(cn1); break; case WKSID.acos: Trace.Assert(args.Length == 1); if (head(val) == WKSID.times && Ag(val, 1) == _degree) return Numericize(new CompositeExpr(WellKnownSym.acos, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180)))))); if (num1) return Math.Acos(d1); if (cn1 != null) return NArcCos(cn1); break; case WKSID.atan: Trace.Assert(args.Length == 1); if (num1) return Math.Atan(d1); if (cn1 != null) return NArcTan(cn1); break; case WKSID.asec: Trace.Assert(args.Length == 1); if (num1) return Math.Acos(1 / d1); if (cn1 != null) return NArcCos(NReciprocal(cn1)); break; case WKSID.acsc: Trace.Assert(args.Length == 1); if (num1) return Math.Asin(1 / d1); if (cn1 != null) return NArcSin(NReciprocal(cn1)); break; case WKSID.acot: Trace.Assert(args.Length == 1); if (num1) return Math.Atan(1 / d1); if (cn1 != null) return NArcTan(NReciprocal(cn1)); break; case WKSID.sinh: Trace.Assert(args.Length == 1); if (num1) return Math.Sinh(d1); if (cn1 != null) return NSinH(cn1); break; case WKSID.cosh: Trace.Assert(args.Length == 1); if (num1) return Math.Cosh(d1); if (cn1 != null) return NCosH(cn1); break; case WKSID.tanh: Trace.Assert(args.Length == 1); if (num1) return Math.Tanh(d1); if (cn1 != null) return NTanH(cn1); break; case WKSID.sech: Trace.Assert(args.Length == 1); if (num1) return 1 / Math.Cosh(d1); if (cn1 != null) return NReciprocal(NCosH(cn1)); break; case WKSID.csch: Trace.Assert(args.Length == 1); if (num1) return 1 / Math.Sinh(d1); if (cn1 != null) return NReciprocal(NSinH(cn1)); break; case WKSID.coth: Trace.Assert(args.Length == 1); if (num1) return 1 / Math.Tanh(d1); if (cn1 != null) return NReciprocal(NTanH(cn1)); break; case WKSID.asinh: case WKSID.acosh: case WKSID.atanh: case WKSID.asech: case WKSID.acsch: case WKSID.acoth: /* C# library doesn't contain these functions */ break; case WKSID.factorial: Trace.Assert(args.Length == 1); if (in1 != null && in1.Num >= 0) return Factorial(in1.Num); break; case WKSID.summation: Trace.Assert(args.Length > 0 && args.Length < 4); if (args.Length == 3 && num2 && e.Args[0] is CompositeExpr && !(e.Args[2] is NullExpr)) { CompositeExpr ce = e.Args[0] as CompositeExpr; Expr key = new NullExpr(); d1 = 0; if (ce != null && ce.Head == WellKnownSym.equals && (ce.Args[0] is LetterSym || ce.Args[0] is WellKnownSym)) { key = ce.Args[0].Clone(); Expr start = Numericize(ce.Args[1]); IntegerNumber sinn = start as IntegerNumber; DoubleNumber sdn = start as DoubleNumber; d1 = (sinn != null) ? (double)sinn.Num : sdn != null ? sdn.Num : double.NaN; } Expr res = new IntegerNumber(0); for (int d = (int)d1; d1 <= d2 && d <= (int)d2; d++) { Expr newB = (Expr)e.Args[2].Clone(); newB = Numericize(_Substitute(newB, key, d)); res = Plus(res, newB); res = Numericize(_Simplify(res)); } return res; } break; } } return new CompositeExpr(Numericize(e.Head), args); }
public Expr Num(Expr e) { if (e is IntegerNumber) return e; IntegerNumber num = 0; IntegerNumber den = 1; Expr accum = null; switch (head(e)) { case WKSID.times: bool numIsNum = false; List<Expr> fargs1 = flattenMults(e as CompositeExpr); List<Expr> fargs = new List<Expr>(); for (int i = 0; i < fargs1.Count; i++) fargs.Add(Num(fargs1[i])); List<Expr> additions = new List<Expr>(); List<Expr> others = new List<Expr>(); foreach (Expr t in fargs) { if (head(t) == WKSID.plus) additions.Add(t); else others.Add(t); } Expr additiveAccum = null; foreach (Expr t in fargs) { // compute fraction terms Expr tval = Num(t); if (tval == WellKnownSym.infinity) // mult by inf -> inf return WellKnownSym.infinity; DivideExpr div = new DivideExpr(tval); PowerExpr pow = new PowerExpr(tval); if (tval is IntegerNumber) { num.Num = (numIsNum ? num.Num : 1) * (tval as IntegerNumber).Num; numIsNum = true; } else if (pow.OK && pow.PowerInt && pow.IPower < 0) den.Num *= pow.IPower; else if (div.OK && div.DivisorInt) den.Num *= div.IDivisor; else if (head(tval) == WKSID.times && (head(Ag(tval, 0)) == WKSID.plusminus || head(Ag(tval, 1)) == WKSID.plusminus)) if (additiveAccum == null) additiveAccum = tval; else additiveAccum = Mult(additiveAccum, tval); else if (head(tval) == WKSID.times && Ag(tval, 0) is IntegerNumber) { DivideExpr dexp = new DivideExpr(Ag(tval, 1)); if (dexp.OK && dexp.DivisorInt) { // keep integer fractions, leave others unsimplified if (den.Num == dexp.IDivisor) { num.Num *= (Ag(tval, 0) as IntegerNumber).Num; numIsNum = true; } else { num.Num = (Ag(tval, 0) as IntegerNumber).Num * num.Num; den.Num *= dexp.IDivisor; numIsNum = true; } } else if (accum == null) accum = tval; else accum = Mult(accum, tval); } else if (accum == null) accum = tval; else accum = Mult(accum, tval); } if (den.Num == 0 && num.Num == 0) return double.NaN; if (den.Num == 0) return WellKnownSym.infinity; // divide by zero -> infinity if (num.Num == 0 && numIsNum) return 0; // terminate early if we're multiplying by 0 Expr fraction = null; if (numIsNum && (den.Num != 1 || num.Num != 1)) { if ((double)num.Num / (double)den.Num == (int)num.Num / (int)den.Num) // convert frac to integer if possible fraction = (int)(num.Num / den.Num); else if ((double)den.Num / (double)num.Num == (int)(den.Num / num.Num)) // reduce numerator if possible fraction = Divide((int)(den.Num / num.Num)); else fraction = Mult(num, Divide(den)); // fraction } else if (den.Num != 1) fraction = Divide(den); if ((fraction == null || (fraction is IntegerNumber && (fraction as IntegerNumber).Num == 1))) if (accum != null && additiveAccum != null) return Mult(accum, additiveAccum); else if (accum != null) return accum; else if (additiveAccum != null) return additiveAccum; if (fraction != null && accum == null && additiveAccum == null) return fraction; if (fraction == null && accum == null && additiveAccum == null) return 1; if (accum == null) return Plus(fraction, additiveAccum); else if (additiveAccum == null) { if (head(accum) == WKSID.plus) { List<Expr> plusterms = new List<Expr>(); for (int i = 0; i < Args(accum).Length; i++) plusterms.Add(Num(Mult(Args(accum)[i], fraction))); return Plus(plusterms.ToArray()); } return Mult(fraction, accum); } return Plus(Mult(fraction, accum), additiveAccum); case WKSID.factorial: { Expr arg = Num(Ag(e, 0)); if (arg is IntegerNumber && ((IntegerNumber)arg).Num > 0) return Factorial(((IntegerNumber)arg).Num); else return new CompositeExpr(WellKnownSym.factorial, arg); } case WKSID.divide: return Num(Power(Ag(e, 0), -1)); case WKSID.minus: Expr term = Num(Ag(e, 0)); if (term == WellKnownSym.infinity) return WellKnownSym.infinity; if (term is IntegerNumber) return (int)-(term as IntegerNumber).Num; if (term is DoubleNumber) return (double)-(term as DoubleNumber).Num; switch (head(term)) { case WKSID.times: // - (a 4 c) -> a -4 c List<Expr> rem = new List<Expr>(); bool flipped = false; foreach (Expr m in Args(term)) if (!flipped && m is IntegerNumber) { flipped = true; rem.Add((int)-(m as IntegerNumber).Num); } else rem.Add(m); if (flipped) return Mult(rem.ToArray()); break; case WKSID.divide: DivideExpr dexp = new DivideExpr(term); if (dexp.OK && dexp.DivisorInt) return Divide((int)-dexp.IDivisor); break; case WKSID.plus: return Num(Mult(-1, term)); } return Minus(term); case WKSID.mod: { Expr a = Num(Ag(e, 0)); Expr b = Num(Ag(e, 1)); IntegerNumber ia = a as IntegerNumber; IntegerNumber ib = b as IntegerNumber; DoubleNumber da = a as DoubleNumber; DoubleNumber db = b as DoubleNumber; if (ia != null && ib != null) return ia.Num % ib.Num; else if (ia != null && db != null) return Math.IEEERemainder(ia.Num.AsDouble(), db.Num); else if (da != null && ib != null) return Math.IEEERemainder(da.Num, ib.Num.AsDouble()); else if (da != null && db != null) return Math.IEEERemainder(da.Num, db.Num); else return new CompositeExpr(WellKnownSym.mod, a, b); } case WKSID.power: { Expr bas = Num(Ag(e, 0)); Expr pow = Num(Ag(e, 1)); if (head(bas) == WKSID.times) { // distribute (ab)^x -> a^x b^x List<Expr> nargs = new List<Expr>(); foreach (Expr t in Args(bas)) nargs.Add(Power(t, pow)); return Num(Mult(nargs.ToArray())); } if (bas is IntegerNumber && pow is IntegerNumber) { // compute a^b BigInt basI = (bas as IntegerNumber).Num; BigInt powI = (pow as IntegerNumber).Num; Expr powNum = new NullExpr(); try { if (powI == -1) powNum = bas; else powNum = Math.Pow((int)(bas as IntegerNumber), Math.Abs((int)(pow as IntegerNumber))); } catch (Exception) { powNum = new IntegerNumber((int)FSBigInt.Pow(basI.Num, (int)FSBigInt.Abs(powI.Num))); } if ((powNum is DoubleNumber) && (int)(powNum as DoubleNumber).Num == (powNum as DoubleNumber).Num) powNum = (int)((powNum as DoubleNumber).Num); if (powI < 0) return Divide(powNum); return powNum; } if (pow is IntegerNumber) { BigInt powI = (pow as IntegerNumber).Num; if (powI == 1) return bas; // x^1 -> x if (powI == 0) return 1; // x^0 -> 1 } DivideExpr dexp = new DivideExpr(pow); // XXX- hack - x^(a/b) sometimes is an int need symbolic test if (bas is IntegerNumber && dexp.OK && dexp.DivisorInt) { int neg = ((int)(dexp.IDivisor / 2) == ((int)dexp.IDivisor) / 2 && (bas as IntegerNumber).Num < 0) ? -1 : 1; double pd = Math.Pow(neg * (int)(bas as IntegerNumber).Num, 1.0 / (int)dexp.IDivisor); if (Math.Abs(pd - Math.Round(pd)) < 1e-15) { int p = (int)Math.Round(pd); if (neg < 0) { int n = (int)dexp.IDivisor; // (-256)^(1/8) -> -2i // (-128)^(1/7)-> -2 // (-64)^(1/6) -> +-2i // (-32)^(1/5) -> -2 // (-16)^(1/4) -> 2+2i // (-8)^(1/3) -> -2 // (-4)^(1/2) -> 2i if ((n + 1) / 2 == (n + 1) / 2.0) // odd fraction power is -p return -p; if (n == 2) // sqrt is p*imaginary return p == 1 ? (Expr)WellKnownSym.i : Mult(p, WellKnownSym.i); Expr re = Num(Mult(p, Num(new CompositeExpr(WellKnownSym.cos, Mult(WellKnownSym.pi, Divide(n)))))); Expr im = Num(Mult(p, new CompositeExpr(WellKnownSym.sin, Mult(WellKnownSym.pi, Divide(n))))); if (re is RealNumber && im is RealNumber) return new ComplexNumber(re as RealNumber, im as RealNumber); return Mult(Num(Power(Minus(bas), Divide(n))), Power(-1, Divide(n))); } return (int)p; } int mult = 1; BigInt basVal = (bas as IntegerNumber).Num; while (dexp.IDivisor == 2 && (basVal >= 4 || basVal <= -4) && ((int)basVal / 4.0) == (double)(basVal / 4)) { mult *= 2; basVal = basVal / 4; } while (dexp.IDivisor == 2 && (basVal >= 9 || basVal <= -9) && ((int)basVal / 9.0) == (double)(basVal / 9)) { mult *= 3; basVal = basVal / 9; } while (dexp.IDivisor == 2 && (basVal >= 25 || basVal <= -25) && ((int)basVal / 25.0) == (double)(basVal / 25)) { mult *= 5; basVal = basVal / 25; } while (dexp.IDivisor == 2 && (basVal >= 49 || basVal <= -49) && ((int)basVal / 49.0) == (double)(basVal / 49)) { mult *= 7; basVal = basVal / 49; } if (mult != 1) if (basVal != 1) return Mult(mult, Power(new IntegerNumber(basVal), pow)); else return new IntegerNumber(basVal); } if (head(bas) == WKSID.divide) return Num(Divide(Power(Ag(bas, 0), pow))); // (1/x)^a -> x^(-a)bas if (head(bas) == WKSID.power) return Num(Power(Ag(bas, 0), Mult(Ag(bas, 1), pow))); // (x^a)^b -> x^(a*b) RealNumber bnum = bas as RealNumber, pnum = pow as RealNumber; if (bnum != null && pnum != null) { double b = (bnum is IntegerNumber) ? (double)((bnum as IntegerNumber).Num) : (bnum as DoubleNumber).Num; double p = (pnum is IntegerNumber) ? (double)((pnum as IntegerNumber).Num) : (pnum as DoubleNumber).Num; double r = Math.Pow(b, p); if (Math.Abs(r - Math.Round(r)) < 1e-15) return (int)Math.Round(r); return r; } return Power(bas, pow); } case WKSID.root: // nth root (x) -> x ^(1/n) return Num(Power(Ag(e, 0), Divide(Ag(e, 1)))); case WKSID.acos: { Expr val = Num(Ag(e, 0)); return new CompositeExpr(WellKnownSym.acos, val); } case WKSID.magnitude: { Expr val = Num(Ag(e, 0)); if (val is IntegerNumber) return (val as IntegerNumber).Num.abs(); else if (val is DoubleNumber) return Math.Abs((val as DoubleNumber).Num); else return new CompositeExpr(WellKnownSym.magnitude, val); } case WKSID.asin: { Expr val = Num(Ag(e, 0)); return new CompositeExpr(WellKnownSym.asin, val); } case WKSID.atan: { Expr val = Num(Ag(e, 0)); return new CompositeExpr(WellKnownSym.atan, val); } case WKSID.asec: { Expr val = Num(Ag(e, 0)); return new CompositeExpr(WellKnownSym.asec, val); } case WKSID.acsc: { Expr val = Num(Ag(e, 0)); return new CompositeExpr(WellKnownSym.acsc, val); } case WKSID.acot: { Expr val = Num(Ag(e, 0)); return new CompositeExpr(WellKnownSym.acot, val); } case WKSID.sec: { Expr val = Num(Ag(e, 0)); return new CompositeExpr(WellKnownSym.sec, val); } case WKSID.csc: { Expr val = Num(Ag(e, 0)); return new CompositeExpr(WellKnownSym.csc, val); } case WKSID.cot: { Expr val = Num(Ag(e, 0)); return new CompositeExpr(WellKnownSym.cot, val); } case WKSID.cos: { Expr val = Num(Ag(e, 0)); if (val is IntegerNumber && (val as IntegerNumber).Num == 0) //cos(0) -> 1 return 1; return new CompositeExpr(WellKnownSym.cos, val); } case WKSID.index: { ArrayExpr ae = null, ai = null; if (!IsArrayIndex(e, ref ae, ref ai)) return e; int[] inds = ConvertToInd(ai, delegate(Expr ee) { return ExprToInd(Numericize(ee)); }); if (inds == null) return e; return Num(ae[inds]); } case WKSID.sin: { Expr val = Num(Ag(e, 0)); if ((val is IntegerNumber && (val as IntegerNumber).Num == 0)) //sin(0) -> 0 return 0; return new CompositeExpr(WellKnownSym.sin, val); } case WKSID.tan: { Expr val = Num(Ag(e, 0)); if ((val is IntegerNumber && (val as IntegerNumber).Num == 0)) //tan(0) -> 0 return 0; return new CompositeExpr(WellKnownSym.tan, val); } case WKSID.plus: num.Num = 0; foreach (Expr t in Args(e)) { Expr tval = Num(t); if (tval is WellKnownSym && (tval as WellKnownSym).ID == WKSID.infinity) // add infinity -> infinity return WellKnownSym.infinity; if (tval is IntegerNumber) { num.Num += den.Num * (BigInt)tval; // accumulate numerator continue; } if (head(tval) == WKSID.divide && Ag(tval, 0) is IntegerNumber) { // accumulate divisor (& numerator) BigInt oldden = den.Num; BigInt newden = (BigInt)Ag(tval, 0); num.Num *= newden; den.Num *= newden; num.Num += oldden; continue; } if (head(tval) == WKSID.times && Ag(tval, 0) is IntegerNumber) { // accumulate fraction DivideExpr dexp = new DivideExpr(Ag(tval, 1)); if (dexp.OK && dexp.DivisorInt) { // keep integer fractions, leave others unsimplified BigInt oldden = den.Num; BigInt newnum = (BigInt)Ag(tval, 0); BigInt newden = dexp.IDivisor; if (oldden == newden) { num.Num += newnum; } else { num.Num *= newden; den.Num *= newden; num.Num += oldden * newnum; } continue; } } if (accum == null) accum = tval; else accum = Plus(accum, tval); } if (num.Num == 0) { if (accum != null) return accum; return 0; } Expr frac = ((double)num.Num / (double)den.Num == (int)(num.Num / den.Num)) ? (Expr)(int)(num.Num / den.Num) : (Expr)Mult(num, Divide(den)); return accum == null ? frac : Plus(frac, accum); default: if (e is CompositeExpr) { List<Expr> args = new List<Expr>(); foreach (Expr a in Args(e)) args.Add(Num(a)); return new CompositeExpr((e as CompositeExpr).Head.Clone(), args.ToArray()); } break; } return e; }
private Expr _Canonicalize(NullExpr e) { return e; }
public override string Visit(NullExpr e) => "null";
protected override Box __Translate(NullExpr e) { return(new NullBox()); }
public virtual T Visit(NullExpr e) => default(T);