source: trunk/HeuristicLab.Data/3.3/TriangularMatrix.cs @ 15931

Last change on this file since 15931 was 15931, checked in by bburlacu, 3 years ago

#2919: Implement TriangularMatrix deriving from ValueTypeMatrix

File size: 6.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28
29namespace HeuristicLab.Data {
30  [Item("TriangularMatrix", "Represents a lower triangular matrix.")]
31  [StorableClass]
32  public class TriangularMatrix<T> : ValueTypeMatrix<T>, IStringConvertibleMatrix where T : struct {
33    [Storable]
34    private readonly T[] storage;
35
36    private readonly int dimension;
37    private readonly long capacity;
38
39    private TriangularMatrix() { }
40
41    public TriangularMatrix(int dimension) {
42      this.dimension = dimension;
43      capacity = (long)dimension * (dimension + 1) / 2;
44      storage = new T[capacity];
45
46      readOnly = true;
47    }
48
49    [StorableConstructor]
50    protected TriangularMatrix(bool deserializing) : base(deserializing) { }
51
52    protected TriangularMatrix(TriangularMatrix<T> original, Cloner cloner) : base(original, cloner) {
53      capacity = original.capacity;
54      dimension = original.dimension;
55      storage = (T[])original.storage.Clone();
56    }
57
58    public override IDeepCloneable Clone(Cloner cloner) {
59      return new TriangularMatrix<T>(this, cloner);
60    }
61
62    public override int Rows {
63      get { return dimension; }
64      protected set { throw new NotSupportedException(); }
65    }
66
67    public override int Columns {
68      get { return dimension; }
69      protected set { throw new NotSupportedException(); }
70    }
71
72    public int Length { get { return storage.Length; } }
73
74    // the indexing rule for the (lower-)triangular matrix is that always i <= j, otherwise an IndexOutOfBounds exception will occur
75    public override T this[int rowIndex, int columnIndex] {
76      get {
77        if (columnIndex > rowIndex) return default(T); // upper triangular half is zero (default value of T)
78        return storage[rowIndex * (rowIndex + 1) / 2 + columnIndex];
79      }
80      set {
81        if (columnIndex > rowIndex) throw new NotSupportedException();
82        storage[rowIndex * (rowIndex + 1) / 2 + columnIndex] = value;
83      }
84    }
85
86    public T this[int index] {
87      get { return storage[index]; }
88      set { storage[index] = value; }
89    }
90
91    protected virtual string GetValue(int rowIndex, int columnIndex) {
92      return this[rowIndex, columnIndex].ToString(); // see above indexing rule
93    }
94
95    protected virtual bool SetValue(string value, int rowIndex, int columnIndex) {
96      T val;
97      if (!TryParse(value, out val))
98        return false;
99      this[rowIndex, columnIndex] = val;
100      return true;
101    }
102
103    protected virtual bool Validate(string value, out string errorMessage) {
104      T val;
105      errorMessage = "";
106      if (!TryParse(value, out val)) {
107        errorMessage = string.Format("Could not parse string \"{0}\" as {1}.", value, typeof(T));
108        return false;
109      }
110      return true;
111    }
112
113    public override IEnumerator<T> GetEnumerator() {
114      return storage.Cast<T>().GetEnumerator();
115    }
116
117    private static bool TryParse(string value, out T val) {
118      if (typeof(T) == typeof(sbyte)) {
119        sbyte v;
120        if (sbyte.TryParse(value, out v)) {
121          val = (T)(object)v;
122          return true;
123        }
124      } else if (typeof(T) == typeof(byte)) {
125        byte v;
126        if (byte.TryParse(value, out v)) {
127          val = (T)(object)v;
128          return true;
129        }
130      } else if (typeof(T) == typeof(char)) {
131        char v;
132        if (char.TryParse(value, out v)) {
133          val = (T)(object)v;
134          return true;
135        }
136      } else if (typeof(T) == typeof(short)) {
137        short v;
138        if (short.TryParse(value, out v)) {
139          val = (T)(object)v;
140          return true;
141        }
142      } else if (typeof(T) == typeof(ushort)) {
143        ushort v;
144        if (ushort.TryParse(value, out v)) {
145          val = (T)(object)v;
146          return true;
147        }
148      } else if (typeof(T) == typeof(int)) {
149        int v;
150        if (int.TryParse(value, out v)) {
151          val = (T)(object)v;
152          return true;
153        }
154      } else if (typeof(T) == typeof(uint)) {
155        uint v;
156        if (uint.TryParse(value, out v)) {
157          val = (T)(object)v;
158          return true;
159        }
160      } else if (typeof(T) == typeof(long)) {
161        long v;
162        if (long.TryParse(value, out v)) {
163          val = (T)(object)v;
164          return true;
165        }
166      } else if (typeof(T) == typeof(ulong)) {
167        ulong v;
168        if (ulong.TryParse(value, out v)) {
169          val = (T)(object)v;
170          return true;
171        }
172      }
173      val = default(T);
174      return false;
175    }
176
177    public void GetMatrixCoordinates(int index, out int row, out int col) {
178      var root = TriangularRoot(index);
179      row = (int)Math.Floor(root);
180      col = index - row * (row + 1) / 2;
181    }
182
183    private static double TriangularRoot(double x) {
184      return (Math.Sqrt(8 * x + 1) - 1) / 2;
185    }
186
187    #region IStringConvertibleMatrix Members
188    int IStringConvertibleMatrix.Rows {
189      get { return dimension; }
190      set { throw new NotSupportedException("The triangular matrix does not support changing the number of rows."); }
191    }
192
193    int IStringConvertibleMatrix.Columns {
194      get { return dimension; }
195      set { throw new NotSupportedException("The triangular matrix does not support changing the number of columns."); }
196    }
197
198    string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) {
199      return GetValue(rowIndex, columnIndex);
200    }
201
202    bool IStringConvertibleMatrix.SetValue(string value, int rowIndex, int columnIndex) {
203      return SetValue(value, rowIndex, columnIndex);
204    }
205
206    bool IStringConvertibleMatrix.Validate(string value, out string errorMessage) {
207      return Validate(value, out errorMessage);
208    }
209    #endregion
210  }
211}
Note: See TracBrowser for help on using the repository browser.