public static Tensor <Type> operator -(Tensor <Type> x, Tensor <Type> y) { return(Cache.GetValue($"Sub|{x.Id}|{y.Id}", () => { if (x == y) { return Op.ZerosLike(x); } if (x is Elementwise unaryx && unaryx.Abstraction is Scalars.Neg <Type> ) { return -(unaryx.Inputs[0] + y); // (-x) - y = -(x + y) } if (y is Elementwise unaryy && unaryy.Abstraction is Scalars.Neg <Type> ) { return x + unaryy.Inputs[0]; // x - (-y) = x + y } return Op.Apply(x, y, (_x, _y) => _x - _y); //return Option.TakeFirst( // () => x.Match((Neg<Type> neg) => -(neg.x + y)), // () => y.Match((Neg<Type> neg) => x + neg.x), // () => new BinaryElementwise(x, y, (_x, _y) => new Operators.Scalars.Sub<Type>(_x, _y)) //); }));
/// <summary> /// Creates a Tensor from an Abstraction. /// The difference with Elementwise.Create is that we reuse the existing arrays. /// </summary> private Tensor <Type> Lift(Scalar <Type> expr) { if (expr == this.Abstraction) { return(this); } var result = Vars.FirstOrDefault(e => e == expr); if (result != null) { return(Inputs[Array.IndexOf(Vars, expr)]); } // HACK: here the `Clone` only works on some specific cases. switch (expr) { case Scalar <Type> .Binary binary: return(Op.Apply(Lift(binary.x), Lift(binary.y), (_x, _y) => binary.Clone(_x, _y))); case Scalar <Type> .Unary unary: return(Op.Apply(Lift(unary.x), _x => unary.Clone(_x))); case Scalar <Type> .Const cst: return(Op.ConstLike(expr, this)); default: throw new NotImplementedException(); } }
public static Tensor <Type> operator -(Tensor <Type> x) { switch (x) { case Elementwise unary when unary.Abstraction is Scalars.Neg <Type> : return(unary.Inputs[0]); // -(-x) = x case Elementwise binary when binary.Abstraction is Scalars.Sub <Type> : return(binary.Inputs[1] - binary.Inputs[0]); // -(x - y) = y - x case Fill <Type> fill: return(Op.Const(-fill.x, fill.Shape)); case OneHot <Type> oneHot: return(Op.OneHot(oneHot.Shape, oneHot.Index, -oneHot.Content)); default: return(Op.Apply(x, _x => - _x)); } }
public static Tensor <Type> operator +(Tensor <Type> x, Tensor <Type> y) { if (x is Elementwise unaryx && unaryx.Abstraction is Scalars.Neg <Type> ) { return(y - unaryx.Inputs[0]); // (-x) + y = y - x } if (y is Elementwise unaryy && unaryy.Abstraction is Scalars.Neg <Type> ) { return(x - unaryy.Inputs[0]); // x + (-y) = x - y } if (x.IsZero) { return(y); } if (y.IsZero) { return(x); } //() => x.Match((Neg<Type> neg) => y - neg.x), //() => y.Match((Neg<Type> neg) => x - neg.x), return(Op.Apply(x, y, (_x, _y) => _x + _y)); }
public static Tensor <Type> operator +(Scalar <Type> x, Tensor <Type> y) => Op.Apply(y, _y => x + _y);