Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RBFRegression/HeuristicLab.Algorithms.DataAnalysis/3.4/RadialBasisFunctions/MatrixUtilities.cs @ 14386

Last change on this file since 14386 was 14386, checked in by bwerth, 7 years ago

#2699 moved RadialBasisFunctions from Problems.SurrogateProblem to Algorithms.DataAnalysis

File size: 10.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 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.Data;
26
27namespace HeuristicLab.Algorithms.DataAnalysis {
28  internal static class MatrixUtilities {
29
30    public static T[,] To2D<T>(T[][] source) {
31      try {
32        var firstDim = source.Length;
33        var secondDim = source.GroupBy(row => row.Length).Single().Key; // throws InvalidOperationException if source is not rectangular
34        var result = new T[firstDim, secondDim];
35        for (var i = 0; i < firstDim; ++i)
36          for (var j = 0; j < secondDim; ++j)
37            result[i, j] = source[i][j];
38        return result;
39      }
40      catch (InvalidOperationException) {
41        throw new InvalidOperationException("The given jagged array is not rectangular.");
42      }
43    }
44
45    public static DoubleMatrix SortRows(this DoubleMatrix x, int c1) {
46      var sortable = new List<double[]>();
47      for (var i = 0; i < x.Rows; i++)
48        sortable.Add(SelectRow(x, i).ToArray());
49      return new DoubleMatrix(To2D(sortable.OrderBy(p => p[c1]).ToArray()));
50    }
51    public static DoubleMatrix Ones(int rows, int cols) {
52      var val = new double[rows, cols];
53      for (var i = 0; i < rows; i++)
54        for (var j = 0; j < cols; j++)
55          val[i, j] = 1;
56      return new DoubleMatrix(val);
57    }
58    public static DoubleMatrix Identity(int rows, int cols) {
59      var val = new double[rows, cols];
60      for (var i = 0; i < Math.Min(rows, cols); i++)
61        val[i, i] = 1;
62      return new DoubleMatrix(val);
63    }
64    public static DoubleMatrix Elementwise(this DoubleMatrix m, Func<double, double> func) {
65      var val = new double[m.Rows, m.Columns];
66      for (var i = 0; i < m.Rows; i++)
67        for (var j = 0; j < m.Columns; j++)
68          val[i, j] = func.Invoke(m[i, j]);
69      return new DoubleMatrix(val);
70    }
71    public static DoubleMatrix Elementwise(this DoubleMatrix m, DoubleMatrix m1, Func<double, double, double> func) {
72      if (m.Rows != m1.Rows || m.Columns != m1.Columns) throw new ArgumentException("Matrices are of different sizes");
73      var val = new double[m.Rows, m.Columns];
74      for (var i = 0; i < m.Rows; i++)
75        for (var j = 0; j < m.Columns; j++)
76          val[i, j] = func.Invoke(m[i, j], m1[i, j]);
77      return new DoubleMatrix(val);
78    }
79    public static DoubleMatrix Elementwise(this DoubleMatrix m, DoubleMatrix m1, DoubleMatrix m2, Func<double, double, double, double> func) {
80      if (m.Rows != m1.Rows || m.Columns != m1.Columns || m1.Rows != m2.Rows || m1.Columns != m2.Columns) throw new ArgumentException("Matrices are of different sizes");
81      var val = new double[m.Rows, m.Columns];
82      for (var i = 0; i < m.Rows; i++)
83        for (var j = 0; j < m.Columns; j++)
84          val[i, j] = func.Invoke(m[i, j], m1[i, j], m2[i, j]);
85      return new DoubleMatrix(val);
86    }
87    public static DoubleMatrix SelectRow(this DoubleMatrix m, int row) {
88      var m1 = new DoubleMatrix(1, m.Columns);
89      for (var i = 0; i < m.Columns; i++) m1[0, i] = m[row, i];
90      return m1;
91    }
92    public static DoubleMatrix SelectColumn(this DoubleMatrix m, int col) {
93      var m1 = new DoubleMatrix(m.Rows, 1);
94      for (var i = 0; i < m.Rows; i++) m1[i, 0] = m[i, col];
95      return m1;
96    }
97    public static DoubleMatrix RowBind(this DoubleMatrix m1, DoubleMatrix m2) {
98      if (m1.Columns != m2.Columns) throw new ArgumentException("Matrices need to have the same number of columns for RowBind");
99      var m = new DoubleMatrix(m1.Rows + m2.Rows, m1.Columns);
100      for (var i = 0; i < m1.Rows; i++)
101        for (var j = 0; j < m.Columns; j++)
102          m[i, j] = m1[i, j];
103      for (var i = 0; i < m2.Rows; i++)
104        for (var j = 0; j < m.Columns; j++)
105          m[i + m1.Rows, j] = m2[i, j];
106      return m;
107
108    }
109    public static DoubleMatrix ColumnBind(this DoubleMatrix m1, DoubleMatrix m2) {
110      if (m1.Rows != m2.Rows) throw new ArgumentException("Matrices need to have the same number of rows for ColumnBind");
111      var m = new DoubleMatrix(m1.Rows, m1.Columns + m1.Columns);
112      for (var i = 0; i < m1.Rows; i++) {
113        for (var j = 0; j < m1.Columns; j++)
114          m[i, j] = m1[i, j];
115        for (var j = 0; j < m2.Columns; j++)
116          m[i, j + m1.Columns] = m2[i, j];
117      }
118      return m;
119    }
120    public static DoubleMatrix Select(this DoubleMatrix m, int[] rows, int[] cols) {
121      var res = new DoubleMatrix(rows.Length, cols.Length);
122      for (var i = 0; i < res.Rows; i++) {
123        for (var j = 0; j < res.Columns; j++)
124          res[i, j] = m[rows[i], cols[j]];
125      }
126      return res;
127    }
128    public static DoubleMatrix Select(this DoubleMatrix m, int[] rows) {
129      return Select(m, rows, GetIndexVector(m.Columns));
130    }
131    public static int[] GetIndexVector(int size) {
132      var res = new int[size];
133      for (var i = 0; i < size; i++)
134        res[i] = i;
135      return res;
136    }
137    public static DoubleMatrix Transpose(this DoubleMatrix m) {
138      var res = new DoubleMatrix(m.Columns, m.Rows);
139      for (var i = 0; i < res.Rows; i++)
140        for (var j = 0; j < res.Columns; j++)
141          res[i, j] = m[j, i];
142      return res;
143    }
144    public static DoubleMatrix ToRow(IEnumerable<double> values) {
145      var arr = values.ToArray();
146      var res = new DoubleMatrix(1, arr.Length);
147      for (var i = 0; i < arr.Length; i++) res[0, i] = arr[i];
148      return res;
149    }
150    public static double[] Min(this DoubleMatrix m, int dim) {
151      if (dim != 0 && dim != 1) throw new ArgumentException("Can only find the minimum along rows or colums");
152      var res = new double[dim == 0 ? m.Rows : m.Columns];
153      for (var i = 0; i < res.Length; i++)
154        res[i] = (dim == 0 ? SelectRow(m, i) : SelectColumn(m, i)).Min();
155      return res;
156    }
157    public static double[] Max(this DoubleMatrix m, int dim) {
158      if (dim != 0 && dim != 1) throw new ArgumentException("Can only find the minimum along rows or colums");
159      var res = new double[dim == 0 ? m.Rows : m.Columns];
160      for (var i = 0; i < res.Length; i++)
161        res[i] = (dim == 0 ? SelectRow(m, i) : SelectColumn(m, i)).Max();
162      return res;
163    }
164    public static double[] GetElementVector(int size) {
165      var res = new double[size];
166      for (var d = 1; d <= size; d++) {
167        res[d - 1] = d;
168      }
169      return res;
170    }
171    public static double[] GetRange(double min, double max, int length) {
172      if (length < 2 || min > max) throw new ArgumentException("can not create range of length: " + length + " from " + min + " to " + max);
173      var res = new double[length];
174      var step = (max - min) / (length - 1);
175      res[0] = min;
176      for (var i = 1; i < length; i++)
177        res[i] = step + res[i - 1];
178      return res;
179    }
180    public static int[] GetRange(int min, int max) {
181      if (min > max) throw new ArgumentException("can not create range from " + min + " to " + max);
182      var res = new int[max - min + 1];
183      var i = 0;
184      for (var v = min; v <= max; v++)
185        res[i++] = v;
186      return res;
187    }
188    public static bool IsEqualTo(this DoubleMatrix m1, DoubleMatrix m2) {
189      if (m1.Rows != m2.Rows) return false;
190      if (m1.Columns != m2.Columns) return false;
191      return m1.SequenceEqual(m2);
192    }
193    public static DoubleMatrix ToColumnVector(this IEnumerable<double> values) {
194      var arr = values.ToArray();
195      var res = new DoubleMatrix(arr.Length, 1);
196      for (var i = 0; i < arr.Length; i++)
197        res[i, 0] = arr[i];
198      return res;
199    }
200    public static DoubleMatrix ToMatrix<T>(this IEnumerable<T> rows) where T : IEnumerable<double> {
201      return new DoubleMatrix(To2D(rows.Select(x => x.ToArray()).ToArray())); //not the fastest way to do it
202
203    }
204
205    /// <summary>
206    /// m need to be symmetric positive definit
207    /// </summary>
208    /// <param name="m"></param>
209    /// <returns></returns>
210    public static DoubleMatrix Invert(this DoubleMatrix m) {
211      int info;
212      alglib.matinvreport report;
213      var upper = m.CloneAsMatrix();
214      alglib.rmatrixinverse(ref upper, out info, out report);
215      if (info != 1) throw new ArgumentException("Could not invert matrix. Is ist quadratic symmetric positive definite?");
216      return new DoubleMatrix(upper);
217    }
218    public static DoubleMatrix Mul(this DoubleMatrix left, DoubleMatrix right) {
219      if (left.Columns != right.Rows) throw new ArgumentException("Dims dont match");
220      var res = new double[left.Rows, right.Columns];
221      alglib.rmatrixgemm(left.Rows, right.Columns, left.Columns, 1, left.CloneAsMatrix(), 0, 0, 0, right.CloneAsMatrix(), 0, 0, 0, 0, ref res, 0, 0);
222      return new DoubleMatrix(res);
223    }
224    public static DoubleMatrix Solve(this DoubleMatrix a, DoubleMatrix b) {
225      if (b.Columns != 1 || a.Rows != b.Rows) throw new ArgumentException("This system can not be solved due to dimensions");
226      var b1 = b.ToArray();
227      double[] x;
228      int info;
229      alglib.densesolverlsreport denseSolveRep;//what is this used for? In HeuristicLab.Algorithms.DataAnalysis.GaussianProcessSurrogate is a use-case similar to this one. What do you normally do with the rep?
230      alglib.rmatrixsolvels(a.CloneAsMatrix(), a.Rows, a.Columns, b1, 0.0, out info, out denseSolveRep, out x);
231      if (info != 1) {
232        throw new ArgumentException("This system can not be solved due to content or numerics");
233      }
234
235      return x.ToColumnVector();
236    }
237
238  }
239}
Note: See TracBrowser for help on using the repository browser.