io.rtron.math.linear.RealMatrix.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rtron-math Show documentation
Show all versions of rtron-math Show documentation
Component 'rtron-math' of rtron.
The newest version!
/*
* Copyright 2019-2022 Chair of Geoinformatics, Technical University of Munich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.rtron.math.linear
import io.rtron.math.geometry.euclidean.threed.point.Vector3D
import io.rtron.math.std.reshapeByColumnDimension
import org.apache.commons.math3.linear.Array2DRowRealMatrix
import org.apache.commons.math3.linear.MatrixUtils
import org.apache.commons.math3.linear.RealMatrix as CMRealMatrix
/**
* Real matrix of double values.
*
* @param rows the rows of the matrix represented as [DoubleArray]
*/
class RealMatrix(
rows: Array
) {
// Properties and Initializers
init {
require(rows.isNotEmpty()) { "Cannot create matrix without any rows." }
require(rows.all { it.isNotEmpty() }) { "Cannot create matrix with empty columns." }
}
/** adapted matrix class of Commons Math */
private val _matrix: Array2DRowRealMatrix = Array2DRowRealMatrix(rows)
/** entry values of matrix whereby each [DoubleArray] represents a row */
val entries: Array by lazy { _matrix.data }
/** entry values of the matrix flattened to one [DoubleArray] */
val entriesFlattened: DoubleArray get() = entries.flatMap { it.toList() }.toDoubleArray()
/** number of rows */
val rowDimension = _matrix.rowDimension
/** number of columns */
val columnDimension = _matrix.columnDimension
/** dimension of matrix as (rowDimension, columnDimension) */
val dimension get() = Pair(rowDimension, columnDimension)
// Secondary Constructors
constructor(matrix: CMRealMatrix) : this(matrix.data)
constructor(matrix: DoubleArray, columnDimension: Int) : this(matrix.reshapeByColumnDimension(columnDimension))
constructor(rowVectors: List) : this(rowVectors.map { it.toDoubleArray() }.toTypedArray())
// Operators
operator fun get(rowIndex: Int) = getRow(rowIndex)
// Methods
/** Returns true, if any value of the vector is NaN. */
fun containsNaN() = toDoubleArray().any { it.isNaN() }
/** Returns the row of [rowIndex] as double array. */
fun getRow(rowIndex: Int): DoubleArray = _matrix.getRow(rowIndex)!!
/** Returns the row of [rowIndex] as a real matrix. */
fun getRowMatrix(rowIndex: Int): RealMatrix = RealMatrix(_matrix.getRowMatrix(rowIndex))
/** Returns the row of [rowIndex] as real vector. */
fun getRowVector(rowIndex: Int): RealVector = _matrix.getRowVector(rowIndex).toRealVector()
/** Returns the column of [columnIndex] as double array. */
fun getColumn(columnIndex: Int): DoubleArray = _matrix.getColumn(columnIndex)!!
/** Returns the column of [columnIndex] as a real matrix. */
fun getColumnMatrix(columnIndex: Int): RealMatrix = RealMatrix(_matrix.getColumnMatrix(columnIndex))
/** Returns the column of [columnIndex] as real vector. */
fun getColumnVector(columnIndex: Int): RealVector = _matrix.getColumnVector(columnIndex).toRealVector()
/**
* Returns a submatrix of the complete matrix by only selecting the [selectedRows] and [selectedColumns].
*
* @param selectedRows selected row indices
* @param selectedColumns selected column indices
* @return submatrix
*/
fun getSubMatrix(selectedRows: IntArray, selectedColumns: IntArray) =
RealMatrix(_matrix.getSubMatrix(selectedRows, selectedColumns))
/**
* Returns a submatrix of the complete matrix by only selecting the [selectedRows] and [selectedColumns].
*
* @param selectedRows selected row indices
* @param selectedColumns selected column indices
* @return submatrix
*/
fun getSubMatrix(selectedRows: IntRange, selectedColumns: IntRange) =
getSubMatrix(selectedRows.toList().toIntArray(), selectedColumns.toList().toIntArray())
/** Returns this matrix multiplied with [other] (return = this x [other]). */
fun multiply(other: RealMatrix) = RealMatrix(_matrix.multiply(other.toRealMatrixCM()))
/** Returns the [other] matrix multiplied with this (return = [other] x this). */
fun preMultiply(other: RealMatrix) = RealMatrix(_matrix.preMultiply(other.toRealMatrixCM()))
/** Returns this matrix multiplied with a [vector] (return = this x [vector]). */
fun multiply(vector: RealVector): RealVector = this.transpose().preMultiply(vector)
/** Returns a [vector] multiplied with this matrix (return = [vector] x this). */
fun preMultiply(vector: RealVector) = _matrix.preMultiply(vector.toVectorCM()).toRealVector()
/** Returns this matrix multiplied with a scalar [factor]. */
fun scalarMultiply(factor: Double) = RealMatrix(_matrix.scalarMultiply(factor))
/** Returns this matrix multiplied with a scalar [summand]. */
fun scalarAdd(summand: Double) = RealMatrix(_matrix.scalarAdd(summand))
/** Returns the transposed matrix of this matrix. */
fun transpose() = RealMatrix(_matrix.transpose())
/** Returns the inverse matrix of this matrix. */
fun inverse() = RealMatrix(MatrixUtils.inverse(_matrix))
fun normalize(rowIndex: Int, columnIndex: Int): RealMatrix {
require(this[rowIndex][columnIndex] != 0.0) { "Normalizing element must not be zero." }
return scalarMultiply(1.0 / this[rowIndex][columnIndex])
}
override fun hashCode(): Int {
return _matrix.hashCode()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as RealMatrix
if (dimension != other.dimension) return false
if (!entries.contentEquals(other.entries)) return false
return true
}
// Conversions
fun toDoubleArray(): DoubleArray = _matrix.data.flatMap { it.asIterable() }.toDoubleArray()
fun toDoubleList(): List = _matrix.data.flatMap { it.asIterable() }.toList()
/** Conversion to adapted Real Matrix class from Apache Commons Math. */
fun toRealMatrixCM(): CMRealMatrix = _matrix
override fun toString(): String {
return "Matrix(_matrix=$_matrix)"
}
companion object {
/**
* Creates a [RealMatrix] from a list of column [RealVector].
*
* @param columnVectors list of column vectors that must have the same dimension
*/
@kotlin.jvm.JvmName("ofListRealVector")
fun of(columnVectors: List): RealMatrix {
val rowDimension = columnVectors.first().dimension
require(columnVectors.isNotEmpty()) { "No column vectors provided for building a matrix." }
require(columnVectors.all { it.dimension == rowDimension }) { "Provided column vectors have different dimensions." }
val matrixValues = (0 until rowDimension).fold(emptyList()) { acc, currentRowIndex -> acc + columnVectors.map { it[currentRowIndex] }.toDoubleArray() }
return RealMatrix(matrixValues.toTypedArray())
}
/**
* Creates a [RealMatrix] from a list of 3D vectors
*
* @param vectors list of 3D vectors whereby each vector will be represented as a row
*/
@kotlin.jvm.JvmName("ofListVector3D")
fun of(vectors: List): RealMatrix =
RealMatrix(vectors.map { it.toRealVector() })
/**
* Creates an identity [RealMatrix] of the [dimension].
*/
fun ofIdentity(dimension: Int): RealMatrix {
require(dimension > 0) { "Dimension must be greater than 0." }
val cmMatrix = MatrixUtils.createRealIdentityMatrix(dimension)
return RealMatrix(cmMatrix)
}
/**
* Creates a [RealMatrix] with [diagonal] entries.
*
* @param diagonal entry values for matrix diagonal
*/
fun ofDiagonal(diagonal: RealVector): RealMatrix {
require(diagonal.dimension > 0) { "Dimension of diagonal must be greater than 0." }
val cmMatrix = MatrixUtils.createRealDiagonalMatrix(diagonal.toDoubleArray())
return RealMatrix(cmMatrix)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy