using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace HeuristicLab.Problems.DataAnalysis.Symbolic { /// /// A sparse vector of algebraic types. Elements are accessed via a key of type K /// /// Key type /// Element type [DebuggerDisplay("SparseVector: {ToString()}")] public sealed class AlgebraicSparseVector : IAlgebraicType> where T : IAlgebraicType { [DebuggerBrowsable(DebuggerBrowsableState.Never)] private Dictionary elems; public IReadOnlyDictionary Elements => elems; public AlgebraicSparseVector(AlgebraicSparseVector original) { elems = original.elems.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Clone()); } /// /// /// /// /// values are cloned public AlgebraicSparseVector(K[] keys, T[] values) { if (keys.Length != values.Length) throw new ArgumentException("lengths of keys and values doesn't match in SparseVector"); elems = new Dictionary(keys.Length); for (int i = 0; i < keys.Length; ++i) { elems.Add(keys[i], values[i].Clone()); } } public AlgebraicSparseVector() { this.elems = new Dictionary(); } // keep only elements from a private void AssignFromSource(AlgebraicSparseVector a, Func mapAssign) { // remove elems from this which don't occur in a List keysToRemove = new List(); foreach (var kvp in elems) { if (!a.elems.ContainsKey(kvp.Key)) keysToRemove.Add(kvp.Key); } foreach (var o in keysToRemove) elems.Remove(o); // -> zero foreach (var kvp in a.elems) { if (elems.TryGetValue(kvp.Key, out T value)) mapAssign(kvp.Value, value); else elems.Add(kvp.Key, mapAssign(kvp.Value, kvp.Value.Zero)); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public AlgebraicSparseVector Zero => new AlgebraicSparseVector(); [DebuggerBrowsable(DebuggerBrowsableState.Never)] public AlgebraicSparseVector One => throw new NotSupportedException(); public AlgebraicSparseVector Scale(T s) { foreach (var kvp in elems) { kvp.Value.Mul(s); } return this; } public AlgebraicSparseVector Scale(double s) { foreach (var kvp in elems) { kvp.Value.Scale(s); } return this; } public AlgebraicSparseVector Assign(AlgebraicSparseVector a) { elems.Clear(); AssignFromSource(a, (src, dest) => dest.Assign(src)); return this; } public AlgebraicSparseVector AssignInv(AlgebraicSparseVector a) { AssignFromSource(a, (src, dest) => dest.AssignInv(src)); return this; } public AlgebraicSparseVector AssignNeg(AlgebraicSparseVector a) { AssignFromSource(a, (src, dest) => dest.AssignNeg(src)); return this; } public AlgebraicSparseVector AssignLog(AlgebraicSparseVector a) { AssignFromSource(a, (src, dest) => dest.AssignLog(src)); return this; } public AlgebraicSparseVector AssignExp(AlgebraicSparseVector a) { AssignFromSource(a, (src, dest) => dest.AssignExp(src)); return this; } public AlgebraicSparseVector AssignIntPower(AlgebraicSparseVector a, int p) { AssignFromSource(a, (src, dest) => dest.AssignIntPower(src, p)); return this; } public AlgebraicSparseVector AssignIntRoot(AlgebraicSparseVector a, int r) { AssignFromSource(a, (src, dest) => dest.AssignIntRoot(src, r)); return this; } public AlgebraicSparseVector AssignSin(AlgebraicSparseVector a) { AssignFromSource(a, (src, dest) => dest.AssignSin(src)); return this; } public AlgebraicSparseVector AssignCos(AlgebraicSparseVector a) { AssignFromSource(a, (src, dest) => dest.AssignCos(src)); return this; } public AlgebraicSparseVector AssignTanh(AlgebraicSparseVector a) { AssignFromSource(a, (src, dest) => dest.AssignTanh(src)); return this; } public AlgebraicSparseVector AssignAbs(AlgebraicSparseVector a) { AssignFromSource(a, (src, dest) => dest.AssignAbs(src)); return this; } public AlgebraicSparseVector AssignSgn(AlgebraicSparseVector a) { AssignFromSource(a, (src, dest) => dest.AssignSgn(src)); return this; } public AlgebraicSparseVector Add(AlgebraicSparseVector a) { foreach (var kvp in a.elems) { if (elems.TryGetValue(kvp.Key, out T value)) value.Add(kvp.Value); else elems.Add(kvp.Key, kvp.Value.Clone()); // 0 + a } return this; } public AlgebraicSparseVector Sub(AlgebraicSparseVector a) { foreach (var kvp in a.elems) { if (elems.TryGetValue(kvp.Key, out T value)) value.Sub(kvp.Value); else elems.Add(kvp.Key, kvp.Value.Zero.Sub(kvp.Value)); // 0 - a } return this; } public AlgebraicSparseVector Mul(AlgebraicSparseVector a) { var keys = elems.Keys.ToArray(); foreach (var k in keys) if (!a.elems.ContainsKey(k)) elems.Remove(k); // 0 * a => 0 foreach (var kvp in a.elems) { if (elems.TryGetValue(kvp.Key, out T value)) value.Mul(kvp.Value); // this * a } return this; } public AlgebraicSparseVector Div(AlgebraicSparseVector a) { return Mul(a.Clone().Inv()); } public AlgebraicSparseVector AssignMin(AlgebraicSparseVector other) { // assumes that keys without a matching key in other are zero and vice versa foreach (var kvp in elems) if (!other.elems.ContainsKey(kvp.Key)) kvp.Value.AssignMin(kvp.Value.Zero); // min(v, 0) foreach (var kvp in other.elems) { if (elems.TryGetValue(kvp.Key, out T value)) value.AssignMin(kvp.Value); else elems.Add(kvp.Key, kvp.Value.Zero.AssignMin(kvp.Value)); } return this; } public AlgebraicSparseVector AssignMax(AlgebraicSparseVector other) { // assumes that keys without a matching key in other are zero and vice versa foreach (var kvp in elems) if (!other.elems.ContainsKey(kvp.Key)) kvp.Value.AssignMax(kvp.Value.Zero); // max(v, 0) foreach (var kvp in other.elems) { if (elems.TryGetValue(kvp.Key, out T value)) value.AssignMax(kvp.Value); else elems.Add(kvp.Key, kvp.Value.Zero.AssignMax(kvp.Value)); } return this; } public AlgebraicSparseVector Clone() { return new AlgebraicSparseVector(this); } public override string ToString() { return "[" + string.Join(" ", elems.Select(kvp => kvp.Key + ": " + kvp.Value)) + "]"; } } }