15b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass/* 25b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Copyright (C) 2017 The Android Open Source Project 35b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 45b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Licensed under the Apache License, Version 2.0 (the "License"); 55b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * you may not use this file except in compliance with the License. 65b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * You may obtain a copy of the License at 75b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 85b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * http://www.apache.org/licenses/LICENSE-2.0 95b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 105b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Unless required by applicable law or agreed to in writing, software 115b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * distributed under the License is distributed on an "AS IS" BASIS, 125b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * See the License for the specific language governing permissions and 145b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * limitations under the License. 155b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 165b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 175b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plasspackage com.android.server.wifi.util; 185b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 195b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass/** 205b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Utility for doing basic matix calculations 215b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 225b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plasspublic class Matrix { 235b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public final int n; 245b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public final int m; 255b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public final double[] mem; 265b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 275b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 285b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Creates a new matrix, initialized to zeros 295b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 305b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param rows - number of rows (n) 315b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param cols - number of columns (m) 325b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 335b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix(int rows, int cols) { 345b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass n = rows; 355b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass m = cols; 365b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass mem = new double[rows * cols]; 375b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 385b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 395b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 405b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Creates a new matrix using the provided array of values 415b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * <p> 425b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Values are in row-major order. 435b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 445b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param stride is the number of columns. 455b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param values is the array of values. 465b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IllegalArgumentException if length of values array not a multiple of stride 475b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 485b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix(int stride, double[] values) { 495b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass n = (values.length + stride - 1) / stride; 505b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass m = stride; 515b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass mem = values; 525b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (mem.length != n * m) throw new IllegalArgumentException(); 535b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 545b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 555b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 565b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Creates a new matrix duplicating the given one 575b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 585b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param that is the source Matrix. 595b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 605b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix(Matrix that) { 615b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass n = that.n; 625b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass m = that.m; 635b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass mem = new double[that.mem.length]; 645b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < mem.length; i++) { 655b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass mem[i] = that.mem[i]; 665b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 675b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 685b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 695b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 705b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Gets the matrix coefficient from row i, column j 715b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 725b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param i row number 735b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param j column number 745b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return Coefficient at i,j 755b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IndexOutOfBoundsException if an index is out of bounds 765b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 775b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public double get(int i, int j) { 785b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (!(0 <= i && i < n && 0 <= j && j < m)) throw new IndexOutOfBoundsException(); 795b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return mem[i * m + j]; 805b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 815b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 825b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 835b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Store a matrix coefficient in row i, column j 845b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 855b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param i row number 865b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param j column number 875b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param v Coefficient to store at i,j 885b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IndexOutOfBoundsException if an index is out of bounds 895b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 905b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public void put(int i, int j, double v) { 915b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (!(0 <= i && i < n && 0 <= j && j < m)) throw new IndexOutOfBoundsException(); 925b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass mem[i * m + j] = v; 935b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 945b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 955b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 965b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Forms the sum of two matrices, this and that 975b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 985b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param that is the other matrix 995b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return newly allocated matrix representing the sum of this and that 1005b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IllegalArgumentException if shapes differ 1015b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 1025b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix plus(Matrix that) { 1035b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return plus(that, new Matrix(n, m)); 1045b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 1055b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 1065b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 1075b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 1085b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Forms the sum of two matrices, this and that 1095b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 1105b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param that is the other matrix 1115b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param result is space to hold the result 1125b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return result, filled with the matrix sum 1135b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IllegalArgumentException if shapes differ 1145b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 1155b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix plus(Matrix that, Matrix result) { 1165b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (!(this.n == that.n && this.m == that.m && this.n == result.n && this.m == result.m)) { 1175b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass throw new IllegalArgumentException(); 1185b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 1195b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < mem.length; i++) { 1205b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass result.mem[i] = this.mem[i] + that.mem[i]; 1215b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 1225b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return result; 1235b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 1245b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 1255b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 1265b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Forms the difference of two matrices, this and that 1275b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 1285b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param that is the other matrix 1295b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return newly allocated matrix representing the difference of this and that 1305b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IllegalArgumentException if shapes differ 1315b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 1325b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix minus(Matrix that) { 1335b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return minus(that, new Matrix(n, m)); 1345b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 1355b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 1365b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 1375b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Forms the difference of two matrices, this and that 1385b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 1395b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param that is the other matrix 1405b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param result is space to hold the result 1415b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return result, filled with the matrix difference 1425b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IllegalArgumentException if shapes differ 1435b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 1445b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix minus(Matrix that, Matrix result) { 1455b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (!(this.n == that.n && this.m == that.m && this.n == result.n && this.m == result.m)) { 1465b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass throw new IllegalArgumentException(); 1475b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 1485b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < mem.length; i++) { 1495b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass result.mem[i] = this.mem[i] - that.mem[i]; 1505b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 1515b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return result; 1525b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 1535b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 1545b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 15551bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * Forms a scalar product 15651bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * 15751bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @param scalar is the value to multiply by 15851bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @return newly allocated matrix representing the product this and scalar 15951bb91940298ca771a98591f8682a02ebe4bca12Michael Plass */ 16051bb91940298ca771a98591f8682a02ebe4bca12Michael Plass public Matrix times(double scalar) { 16151bb91940298ca771a98591f8682a02ebe4bca12Michael Plass return times(scalar, new Matrix(n, m)); 16251bb91940298ca771a98591f8682a02ebe4bca12Michael Plass } 16351bb91940298ca771a98591f8682a02ebe4bca12Michael Plass 16451bb91940298ca771a98591f8682a02ebe4bca12Michael Plass /** 16551bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * Forms a scalar product 16651bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * 16751bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @param scalar is the value to multiply by 16851bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @param result is space to hold the result 16951bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @return result, filled with the matrix difference 17051bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @throws IllegalArgumentException if shapes differ 17151bb91940298ca771a98591f8682a02ebe4bca12Michael Plass */ 17251bb91940298ca771a98591f8682a02ebe4bca12Michael Plass public Matrix times(double scalar, Matrix result) { 17351bb91940298ca771a98591f8682a02ebe4bca12Michael Plass if (!(this.n == result.n && this.m == result.m)) { 17451bb91940298ca771a98591f8682a02ebe4bca12Michael Plass throw new IllegalArgumentException(); 17551bb91940298ca771a98591f8682a02ebe4bca12Michael Plass } 17651bb91940298ca771a98591f8682a02ebe4bca12Michael Plass for (int i = 0; i < mem.length; i++) { 17751bb91940298ca771a98591f8682a02ebe4bca12Michael Plass result.mem[i] = this.mem[i] * scalar; 17851bb91940298ca771a98591f8682a02ebe4bca12Michael Plass } 17951bb91940298ca771a98591f8682a02ebe4bca12Michael Plass return result; 18051bb91940298ca771a98591f8682a02ebe4bca12Michael Plass } 18151bb91940298ca771a98591f8682a02ebe4bca12Michael Plass 18251bb91940298ca771a98591f8682a02ebe4bca12Michael Plass /** 1835b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Forms the matrix product of two matrices, this and that 1845b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 1855b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param that is the other matrix 1865b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return newly allocated matrix representing the matrix product of this and that 1875b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IllegalArgumentException if shapes are not conformant 1885b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 1895b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix dot(Matrix that) { 1905b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return dot(that, new Matrix(this.n, that.m)); 1915b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 1925b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 1935b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 1945b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Forms the matrix product of two matrices, this and that 1955b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * <p> 1965b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Caller supplies an object to contain the result, as well as scratch space 1975b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 1985b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param that is the other matrix 1995b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param result is space to hold the result 2005b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return result, filled with the matrix product 2015b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IllegalArgumentException if shapes are not conformant 2025b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 2035b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix dot(Matrix that, Matrix result) { 2045b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (!(this.n == result.n && this.m == that.n && that.m == result.m)) { 2055b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass throw new IllegalArgumentException(); 2065b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2075b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < n; i++) { 2085b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int j = 0; j < that.m; j++) { 2095b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass double s = 0.0; 2105b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int k = 0; k < m; k++) { 2115b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass s += this.get(i, k) * that.get(k, j); 2125b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2135b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass result.put(i, j, s); 2145b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2155b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2165b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return result; 2175b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2185b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 2195b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 2205b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Forms the matrix transpose 2215b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 2225b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return newly allocated transpose matrix 2235b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 2245b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix transpose() { 2255b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return transpose(new Matrix(m, n)); 2265b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2275b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 2285b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 2295b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Forms the matrix transpose 2305b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * <p> 2315b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Caller supplies an object to contain the result 2325b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 2335b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param result is space to hold the result 2345b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return result, filled with the matrix transpose 2355b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IllegalArgumentException if result shape is wrong 2365b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 2375b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix transpose(Matrix result) { 2385b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (!(this.n == result.m && this.m == result.n)) throw new IllegalArgumentException(); 2395b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < n; i++) { 2405b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int j = 0; j < m; j++) { 2415b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass result.put(j, i, get(i, j)); 2425b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2435b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2445b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return result; 2455b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2465b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 2475b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 2485b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Forms the inverse of a square matrix 2495b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 2505b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return newly allocated matrix representing the matrix inverse 2515b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws ArithmeticException if the matrix is not invertible 2525b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 2535b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix inverse() { 2545b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return inverse(new Matrix(n, m), new Matrix(n, 2 * m)); 2555b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2565b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 2575b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 2585b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Forms the inverse of a square matrix 2595b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 2605b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param result is space to hold the result 2615b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @param scratch is workspace of dimension n by 2*n 2625b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return result, filled with the matrix inverse 2635b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws ArithmeticException if the matrix is not invertible 2645b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @throws IllegalArgumentException if shape of scratch or result is wrong 2655b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 2665b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public Matrix inverse(Matrix result, Matrix scratch) { 2675b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (!(n == m && n == result.n && m == result.m && n == scratch.n && 2 * m == scratch.m)) { 2685b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass throw new IllegalArgumentException(); 2695b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2705b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 2715b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < n; i++) { 2725b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int j = 0; j < m; j++) { 2735b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass scratch.put(i, j, get(i, j)); 2745b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass scratch.put(i, m + j, i == j ? 1.0 : 0.0); 2755b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2765b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2775b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 2785b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < n; i++) { 2795b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass int ibest = i; 2805b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass double vbest = Math.abs(scratch.get(ibest, ibest)); 2815b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int ii = i + 1; ii < n; ii++) { 2825b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass double v = Math.abs(scratch.get(ii, i)); 2835b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (v > vbest) { 2845b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass ibest = ii; 2855b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass vbest = v; 2865b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2875b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2885b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (ibest != i) { 2895b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int j = 0; j < scratch.m; j++) { 2905b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass double t = scratch.get(i, j); 2915b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass scratch.put(i, j, scratch.get(ibest, j)); 2925b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass scratch.put(ibest, j, t); 2935b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2945b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 2955b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass double d = scratch.get(i, i); 2965b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (d == 0.0) throw new ArithmeticException("Singular matrix"); 2975b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int j = 0; j < scratch.m; j++) { 2985b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass scratch.put(i, j, scratch.get(i, j) / d); 2995b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3005b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int ii = i + 1; ii < n; ii++) { 3015b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass d = scratch.get(ii, i); 3025b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int j = 0; j < scratch.m; j++) { 3035b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass scratch.put(ii, j, scratch.get(ii, j) - d * scratch.get(i, j)); 3045b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3055b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3065b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3075b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = n - 1; i >= 0; i--) { 3085b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int ii = 0; ii < i; ii++) { 3095b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass double d = scratch.get(ii, i); 3105b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int j = 0; j < scratch.m; j++) { 3115b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass scratch.put(ii, j, scratch.get(ii, j) - d * scratch.get(i, j)); 3125b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3135b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3145b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3155b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < result.n; i++) { 3165b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int j = 0; j < result.m; j++) { 3175b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass result.put(i, j, scratch.get(i, m + j)); 3185b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3195b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3205b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return result; 3215b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 32251bb91940298ca771a98591f8682a02ebe4bca12Michael Plass /** 32351bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * Forms the matrix product with the transpose of a second matrix 32451bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * 32551bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @param that is the other matrix 32651bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @return newly allocated matrix representing the matrix product of this and that.transpose() 32751bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @throws IllegalArgumentException if shapes are not conformant 32851bb91940298ca771a98591f8682a02ebe4bca12Michael Plass */ 32951bb91940298ca771a98591f8682a02ebe4bca12Michael Plass public Matrix dotTranspose(Matrix that) { 33051bb91940298ca771a98591f8682a02ebe4bca12Michael Plass return dotTranspose(that, new Matrix(this.n, that.n)); 33151bb91940298ca771a98591f8682a02ebe4bca12Michael Plass } 33251bb91940298ca771a98591f8682a02ebe4bca12Michael Plass 33351bb91940298ca771a98591f8682a02ebe4bca12Michael Plass /** 33451bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * Forms the matrix product with the transpose of a second matrix 33551bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * <p> 33651bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * Caller supplies an object to contain the result, as well as scratch space 33751bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * 33851bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @param that is the other matrix 33951bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @param result is space to hold the result 34051bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @return result, filled with the matrix product of this and that.transpose() 34151bb91940298ca771a98591f8682a02ebe4bca12Michael Plass * @throws IllegalArgumentException if shapes are not conformant 34251bb91940298ca771a98591f8682a02ebe4bca12Michael Plass */ 34351bb91940298ca771a98591f8682a02ebe4bca12Michael Plass public Matrix dotTranspose(Matrix that, Matrix result) { 34451bb91940298ca771a98591f8682a02ebe4bca12Michael Plass if (!(this.n == result.n && this.m == that.m && that.n == result.m)) { 34551bb91940298ca771a98591f8682a02ebe4bca12Michael Plass throw new IllegalArgumentException(); 34651bb91940298ca771a98591f8682a02ebe4bca12Michael Plass } 34751bb91940298ca771a98591f8682a02ebe4bca12Michael Plass for (int i = 0; i < n; i++) { 34851bb91940298ca771a98591f8682a02ebe4bca12Michael Plass for (int j = 0; j < that.n; j++) { 34951bb91940298ca771a98591f8682a02ebe4bca12Michael Plass double s = 0.0; 35051bb91940298ca771a98591f8682a02ebe4bca12Michael Plass for (int k = 0; k < m; k++) { 35151bb91940298ca771a98591f8682a02ebe4bca12Michael Plass s += this.get(i, k) * that.get(j, k); 35251bb91940298ca771a98591f8682a02ebe4bca12Michael Plass } 35351bb91940298ca771a98591f8682a02ebe4bca12Michael Plass result.put(i, j, s); 35451bb91940298ca771a98591f8682a02ebe4bca12Michael Plass } 35551bb91940298ca771a98591f8682a02ebe4bca12Michael Plass } 35651bb91940298ca771a98591f8682a02ebe4bca12Michael Plass return result; 35751bb91940298ca771a98591f8682a02ebe4bca12Michael Plass } 3585b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 3595b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 3605b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Tests for equality 3615b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 3625b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass @Override 3635b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public boolean equals(Object that) { 3645b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (this == that) return true; 3655b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (!(that instanceof Matrix)) return false; 3665b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass Matrix other = (Matrix) that; 3675b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (n != other.n) return false; 3685b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (m != other.m) return false; 3695b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < mem.length; i++) { 3705b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (mem[i] != other.mem[i]) return false; 3715b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3725b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return true; 3735b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3745b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 3755b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 3765b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Calculates a hash code 3775b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 3785b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass @Override 3795b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public int hashCode() { 3805b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass int h = n * 101 + m; 3815b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < mem.length; i++) { 3825b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass h = h * 37 + Double.hashCode(mem[i]); 3835b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3845b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return h; 3855b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 3865b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 3875b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass /** 3885b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * Makes a string representation 3895b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * 3905b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass * @return string like "[a, b; c, d]" 3915b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass */ 3925b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass @Override 3935b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass public String toString() { 3945b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass StringBuilder sb = new StringBuilder(n * m * 8); 3955b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass sb.append("["); 3965b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass for (int i = 0; i < mem.length; i++) { 3975b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass if (i > 0) sb.append(i % m == 0 ? "; " : ", "); 3985b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass sb.append(mem[i]); 3995b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 4005b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass sb.append("]"); 4015b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass return sb.toString(); 4025b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass } 4035b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass 4045b0fa1e4851b9f4a8fd8efe7afa89b575be727bdMichael Plass} 405