Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2965_CancelablePersistence/HeuristicLab.Data/3.3/TriangularMatrix.cs @ 16654

Last change on this file since 16654 was 15932, checked in by bburlacu, 7 years ago

#2919: Decide to enforce symmetry by returning values mirrored across the main diagonal.

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        // provide symmetry of returned values
78        if (columnIndex > rowIndex) return this[columnIndex, rowIndex];
79        return storage[rowIndex * (rowIndex + 1) / 2 + columnIndex];
80      }
81      set {
82        if (columnIndex > rowIndex) this[columnIndex, rowIndex] = value;
83        else storage[rowIndex * (rowIndex + 1) / 2 + columnIndex] = value;
84      }
85    }
86
87    public T this[int index] {
88      get { return storage[index]; }
89      set { storage[index] = value; }
90    }
91
92    protected virtual string GetValue(int rowIndex, int columnIndex) {
93      return this[rowIndex, columnIndex].ToString(); // see above indexing rule
94    }
95
96    protected virtual bool SetValue(string value, int rowIndex, int columnIndex) {
97      T val;
98      if (!TryParse(value, out val))
99        return false;
100      this[rowIndex, columnIndex] = val;
101      return true;
102    }
103
104    protected virtual bool Validate(string value, out string errorMessage) {
105      T val;
106      errorMessage = "";
107      if (!TryParse(value, out val)) {
108        errorMessage = string.Format("Could not parse string \"{0}\" as {1}.", value, typeof(T));
109        return false;
110      }
111      return true;
112    }
113
114    public override IEnumerator<T> GetEnumerator() {
115      return storage.Cast<T>().GetEnumerator();
116    }
117
118    private static bool TryParse(string value, out T val) {
119      if (typeof(T) == typeof(sbyte)) {
120        sbyte v;
121        if (sbyte.TryParse(value, out v)) {
122          val = (T)(object)v;
123          return true;
124        }
125      } else if (typeof(T) == typeof(byte)) {
126        byte v;
127        if (byte.TryParse(value, out v)) {
128          val = (T)(object)v;
129          return true;
130        }
131      } else if (typeof(T) == typeof(char)) {
132        char v;
133        if (char.TryParse(value, out v)) {
134          val = (T)(object)v;
135          return true;
136        }
137      } else if (typeof(T) == typeof(short)) {
138        short v;
139        if (short.TryParse(value, out v)) {
140          val = (T)(object)v;
141          return true;
142        }
143      } else if (typeof(T) == typeof(ushort)) {
144        ushort v;
145        if (ushort.TryParse(value, out v)) {
146          val = (T)(object)v;
147          return true;
148        }
149      } else if (typeof(T) == typeof(int)) {
150        int v;
151        if (int.TryParse(value, out v)) {
152          val = (T)(object)v;
153          return true;
154        }
155      } else if (typeof(T) == typeof(uint)) {
156        uint v;
157        if (uint.TryParse(value, out v)) {
158          val = (T)(object)v;
159          return true;
160        }
161      } else if (typeof(T) == typeof(long)) {
162        long v;
163        if (long.TryParse(value, out v)) {
164          val = (T)(object)v;
165          return true;
166        }
167      } else if (typeof(T) == typeof(ulong)) {
168        ulong v;
169        if (ulong.TryParse(value, out v)) {
170          val = (T)(object)v;
171          return true;
172        }
173      }
174      val = default(T);
175      return false;
176    }
177
178    public void GetMatrixCoordinates(int index, out int row, out int col) {
179      var root = TriangularRoot(index);
180      row = (int)Math.Floor(root);
181      col = index - row * (row + 1) / 2;
182    }
183
184    private static double TriangularRoot(double x) {
185      return (Math.Sqrt(8 * x + 1) - 1) / 2;
186    }
187
188    #region IStringConvertibleMatrix Members
189    int IStringConvertibleMatrix.Rows {
190      get { return dimension; }
191      set { throw new NotSupportedException("The triangular matrix does not support changing the number of rows."); }
192    }
193
194    int IStringConvertibleMatrix.Columns {
195      get { return dimension; }
196      set { throw new NotSupportedException("The triangular matrix does not support changing the number of columns."); }
197    }
198
199    string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) {
200      return GetValue(rowIndex, columnIndex);
201    }
202
203    bool IStringConvertibleMatrix.SetValue(string value, int rowIndex, int columnIndex) {
204      return SetValue(value, rowIndex, columnIndex);
205    }
206
207    bool IStringConvertibleMatrix.Validate(string value, out string errorMessage) {
208      return Validate(value, out errorMessage);
209    }
210    #endregion
211  }
212}
Note: See TracBrowser for help on using the repository browser.