Free cookie consent management tool by TermsFeed Policy Generator

source: branches/NCA/HeuristicLab.Algorithms.NCA/3.3/Matrix.cs @ 8422

Last change on this file since 8422 was 8422, checked in by abeham, 12 years ago

#1913:

  • Reduced memory footprint
  • Fixed some bugs
  • Added some tests
File size: 6.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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;
24using System.Collections.Generic;
25using System.Linq;
26using HeuristicLab.Common;
27using HeuristicLab.PluginInfrastructure;
28
29namespace HeuristicLab.Algorithms.NCA {
30  [NonDiscoverableType]
31  internal class Matrix : IEnumerable<double>, IDeepCloneable {
32
33    private IEnumerable<double> values;
34    private bool isTransposed;
35    private int rows, columns;
36    public int Rows {
37      get {
38        if (!isTransposed) return rows;
39        else return columns;
40      }
41      private set {
42        if (!isTransposed) rows = value;
43        else columns = value;
44      }
45    }
46    public int Columns {
47      get {
48        if (!isTransposed) return columns;
49        else return rows;
50      }
51      private set {
52        if (!isTransposed) columns = value;
53        else rows = value;
54      }
55    }
56
57    protected Matrix(Matrix original, Cloner cloner) {
58      this.values = original.values.ToArray();
59      this.isTransposed = original.isTransposed;
60      this.rows = original.rows;
61      this.columns = original.columns;
62      cloner.RegisterClonedObject(original, this);
63    }
64    public Matrix(IEnumerable<double> vector) {
65      this.values = vector;
66      Rows = 1;
67      Columns = vector.Count();
68    }
69    public Matrix(IEnumerable<double> vector, int length) {
70      this.values = vector;
71      Rows = 1;
72      Columns = length;
73    }
74    public Matrix(double[,] matrix) {
75      this.values = GetOnlineValues(matrix);
76      Rows = matrix.GetLength(0);
77      Columns = matrix.GetLength(1);
78    }
79    public Matrix(IEnumerable<double> matrix, int rows, int columns) {
80      this.values = matrix;
81      Rows = rows;
82      Columns = columns;
83    }
84
85    public object Clone() {
86      return Clone(new Cloner());
87    }
88    public IDeepCloneable Clone(Cloner cloner) {
89      return new Matrix(this, cloner);
90    }
91
92    public Matrix Transpose() {
93      var result = new Matrix(values, Rows, Columns);
94      result.isTransposed = true;
95      return result;
96    }
97
98    public Matrix Add(Matrix other) {
99      return new Matrix(AddOnline(other), Rows, Columns);
100    }
101
102    public void AddTo(double[,] matrix) {
103      if (Rows != matrix.GetLength(0) || Columns != matrix.GetLength(1)) throw new ArgumentException("unequal size", "matrix");
104      var iter = values.GetEnumerator();
105      for (int i = 0; i < Rows; i++)
106        for (int j = 0; j < Columns; j++) {
107          iter.MoveNext();
108          matrix[i, j] += iter.Current;
109        }
110    }
111
112    public Matrix Subtract(Matrix other) {
113      return new Matrix(SubtractOnline(other), Rows, Columns);
114    }
115
116    public Matrix Multiply(Matrix other) {
117      return new Matrix(MultiplyOnline(other), Rows, other.Columns);
118    }
119
120    public Matrix Multiply(double value) {
121      return new Matrix(values.Select(x => x * value), Rows, Columns);
122    }
123
124    public double Length() {
125      if (Rows != 1) throw new ArgumentException("Length only works on vectors.");
126      return Math.Sqrt(values.Sum(x => x * x));
127    }
128
129    public Matrix OuterProduct(Matrix other) {
130      if (Rows != 1 || other.Rows != 1) throw new ArgumentException("OuterProduct can only be applied to vectors.");
131      return Transpose().Multiply(other);
132    }
133
134    public Matrix Negate() {
135      return new Matrix(values.Select(x => -x), Rows, Columns);
136    }
137
138    public Matrix Apply() {
139      return new Matrix(values.ToArray(), Rows, Columns);
140    }
141
142    public IEnumerator<double> GetEnumerator() { return values.GetEnumerator(); }
143    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
144
145
146    private IEnumerable<double> AddOnline(Matrix other) {
147      if (Rows != other.Rows || Columns != other.Columns) throw new ArgumentException("Number of rows and columns are not equal.");
148      var meIter = values.GetEnumerator();
149      var otherIter = other.GetEnumerator();
150      if (!meIter.MoveNext()) yield break;
151      if (!otherIter.MoveNext()) yield break;
152      for (int i = 0; i < Rows * Columns; i++) {
153        yield return meIter.Current + otherIter.Current;
154        meIter.MoveNext();
155        otherIter.MoveNext();
156      }
157    }
158
159    private IEnumerable<double> SubtractOnline(Matrix other) {
160      if (Rows != other.Rows || Columns != other.Columns) throw new ArgumentException("Number of rows and columns are not equal.");
161      var meIter = values.GetEnumerator();
162      var otherIter = other.GetEnumerator();
163      if (!meIter.MoveNext()) yield break;
164      if (!otherIter.MoveNext()) yield break;
165      for (int i = 0; i < Rows * Columns; i++) {
166        yield return meIter.Current - otherIter.Current;
167        meIter.MoveNext();
168        otherIter.MoveNext();
169      }
170    }
171
172    private IEnumerable<double> MultiplyOnline(Matrix other) {
173      if (Columns != other.Rows) throw new ArgumentException("Number of rows and columns are not equal.");
174      var meIter = values.GetEnumerator();
175      var otherByColumn = other.Transpose();
176      var otherIter = otherByColumn.GetEnumerator();
177      if (!meIter.MoveNext()) yield break;
178      if (!otherIter.MoveNext()) yield break;
179      for (int r = 0; r < Rows; r++) {
180        var row = new double[Columns];
181        for (int x = 0; x < Columns; x++) {
182          row[x] = meIter.Current;
183          meIter.MoveNext();
184        }
185        for (int c = 0; c < other.Columns; c++) {
186          var sum = 0.0;
187          for (int y = 0; y < other.Rows; y++) {
188            sum += row[y] * otherIter.Current;
189            otherIter.MoveNext();
190          }
191          yield return sum;
192        }
193        otherIter = otherByColumn.GetEnumerator();
194        otherIter.MoveNext();
195      }
196    }
197
198    private IEnumerable<double> GetOnlineValues(double[,] matrix) {
199      if (!isTransposed) {
200        for (int i = 0; i < matrix.GetLength(0); i++)
201          for (int j = 0; j < matrix.GetLength(1); j++) {
202            yield return matrix[i, j];
203          }
204      } else {
205        for (int j = 0; j < matrix.GetLength(1); j++)
206          for (int i = 0; i < matrix.GetLength(0); i++) {
207            yield return matrix[i, j];
208          }
209      }
210    }
211  }
212}
Note: See TracBrowser for help on using the repository browser.