Hullaballoonatic
05/04/2019, 3:01 AMMatrix
class. It extends MutableList<Vector>
(Vector
extends MutableList<Double>
). This allows me to add really nice and intuitive operator functions for row operations like val A = Matrix(5, 5) { i, j -> 1 }
A.row(2) *= 3
A[0] += Vector(0.0, 1.0, 3.0, 4.0, 5.0)
println(A[2]) // < 3.0, 3.0, 3.0, 3.0, 3.0 >
However, column operations aren't going to work the same way because the row and col getters are as so:
fun row(i: Int) = this[i]
fun col(j: Int) = Vector(numRows) { this[it][j] }
so a row operation is performed on the stored Vector from the MutableList, while the col operation is performed on a newly created Vector that wraps the corresponding values.
Does anyone have any ideas how I could allow for col operations in the same intuitive way?karelpeeters
05/04/2019, 6:47 AMVector
an interface, and implement a special type of vector that doesn't store values itself but is backed by the original Matrix
.row
and then change Matrix
to store a flat DoubleArray
instead for a lot better performance.Hullaballoonatic
05/04/2019, 4:54 PMkarelpeeters
05/04/2019, 5:12 PMHullaballoonatic
05/04/2019, 5:12 PMkarelpeeters
05/04/2019, 5:13 PMHullaballoonatic
05/04/2019, 5:14 PMMutableList<Double>
karelpeeters
05/04/2019, 5:15 PMDoubleArray
though. I'd say it depends, are you planning to use those vectors in a list-like way a lot? You can't change their size, so it's already not really going to be a mutable list.Hullaballoonatic
05/04/2019, 5:16 PMkarelpeeters
05/04/2019, 5:17 PM(Mutable)MatrixSlice
that work better and have functions like subSlice
.Hullaballoonatic
05/04/2019, 5:19 PMkarelpeeters
05/04/2019, 5:21 PMMutableList
from scratch is quite difficult, and you could choose a simpler interface yourself. But if you have no need for such an abstraction then just don't do it 😒imple_smile:Hullaballoonatic
05/04/2019, 5:22 PMkarelpeeters
05/04/2019, 5:23 PMMatrix
a List
?Hullaballoonatic
05/04/2019, 5:24 PMkarelpeeters
05/04/2019, 5:27 PMHullaballoonatic
05/04/2019, 5:27 PMopen class Matrix(data: List<List<Double>> = listOf()) : MutableList<Vector> by data.map({ it.toVector() }).toMutableList()
karelpeeters
05/04/2019, 5:28 PMList
also gets to access to Kotlin's collections functions.Hullaballoonatic
05/04/2019, 5:29 PMkarelpeeters
05/04/2019, 5:29 PM.map{}.toMutableList{}
is terribly inefficient, it copies the whole list over for no reason. Use mapTo
instead.Hullaballoonatic
05/04/2019, 5:30 PMkarelpeeters
05/04/2019, 5:35 PMget(r,c) = arr[r*width + c]
and corresponding set(r,c,v)
and everything else can stay about the same, right?Hullaballoonatic
05/04/2019, 5:36 PMas Vector
instead of to Vector
and thus operations would be performed on the matrix?fun col(index: Int) = List(numRows) { this[it][index] } as Vector
karelpeeters
05/04/2019, 7:12 PMinterface Vector {
val size: Int
operator fun get(i: Int): Double
}
fun Vector(elements: DoubleArray): Vector = BasicVector(elements)
private class BasicVector(val arr: DoubleArray): Vector {
override val size: Int get() = arr.size
override fun get(i: Int) = arr[i]
}
class Matrix(val width: Int, val height: Int) {
private val arr = DoubleArray(width * height)
private fun index(row: Int, col: Int) = row * width + col
operator fun get(row: Int, col: Int) = arr[index(row, col)]
operator fun set(row: Int, col: Int, value: Double) { arr[index(row, col)] = value }
operator fun get(row: Int) = row(row)
fun row(row: Int): Vector = RowVector(row)
fun col(col: Int): Vector = ColVector(col)
private inner class RowVector(val row: Int): Vector {
override val size: Int get() = this@Matrix.width
override fun get(i: Int) = this@Matrix[row, i]
}
private inner class ColVector(val col: Int): Vector {
override val size: Int get() = this@Matrix.height
override fun get(i: Int) = this@Matrix[i, col]
}
}
Hullaballoonatic
05/04/2019, 7:12 PMkarelpeeters
05/04/2019, 7:12 PMHullaballoonatic
05/04/2019, 7:13 PMkarelpeeters
05/04/2019, 7:14 PMHullaballoonatic
05/04/2019, 7:14 PMkarelpeeters
05/04/2019, 7:15 PMHullaballoonatic
05/04/2019, 7:15 PMkarelpeeters
05/04/2019, 7:16 PMHullaballoonatic
05/04/2019, 7:16 PMkarelpeeters
05/04/2019, 7:18 PMMatrix
and adding stuff, do this instead:
class DataFrame {
val matrix: Matrix = ...
val fileName: String = ...
...
}
Hullaballoonatic
05/04/2019, 7:19 PMkarelpeeters
05/04/2019, 7:20 PMHullaballoonatic
05/04/2019, 7:20 PMkarelpeeters
05/04/2019, 7:21 PMHullaballoonatic
05/04/2019, 7:22 PMthis@Matrix.foo
. that's greataddAll
in the correct place or repeatedly performing removeAt
in the correct placefun addCol(j: Int, col: List<Double> = List(numRows) { 0.0 }): Vector {
if (col.size != numRows)
throw IllegalArgumentException("Column does not have number of values equal to number of entries in matrix.")
width++
repeat(numRows) { i -> add(i * width + j, col[i]) }
return col(j)
}
fun removeCol(j: Int = lastColIndex): Vector {
val res = mutableListOf<Double>() as Vector
width--
repeat(numRows) { i -> res += removeAt(i * width + j) }
return res
}
karelpeeters
05/05/2019, 8:06 AM+
and -
between a col/row of a matrix and a vector, mutating the matrix?Hullaballoonatic
05/05/2019, 9:05 PMkarelpeeters
05/05/2019, 9:06 PMHullaballoonatic
05/05/2019, 9:06 PMkarelpeeters
05/05/2019, 9:06 PMHullaballoonatic
05/05/2019, 9:11 PMmutableList
vs List
function in memory+
and -
operators for adding and removing rows from the matrixaddRow
and addCol
karelpeeters
05/05/2019, 9:12 PMHullaballoonatic
05/05/2019, 9:13 PMkarelpeeters
05/05/2019, 9:15 PMHullaballoonatic
05/05/2019, 9:18 PMkarelpeeters
05/05/2019, 9:18 PMr * width + c
isn't going to work out 😒imple_smile: .Hullaballoonatic
05/05/2019, 9:19 PMkarelpeeters
05/05/2019, 9:19 PMArrayList
and HashMap
, they both preallocate.Hullaballoonatic
05/05/2019, 9:19 PMopen class Matrix(width: Int = 0, values: List<Double> = emptyList()) : MutableList<Double> by values as MutableList
karelpeeters
05/05/2019, 9:21 PMHullaballoonatic
05/05/2019, 9:21 PMkarelpeeters
05/05/2019, 9:21 PMDoubleArray
both for performance and memory.Hullaballoonatic
05/05/2019, 9:22 PMkarelpeeters
05/05/2019, 9:23 PMHullaballoonatic
05/05/2019, 9:23 PMtoDoubleArray
function?karelpeeters
05/05/2019, 9:24 PMHullaballoonatic
05/05/2019, 9:25 PMconstructor(data: List<List<Double>> = listOf()) : this(data[0].size, data.flatten().toDoubleArray())
karelpeeters
05/05/2019, 9:26 PMHullaballoonatic
05/05/2019, 9:26 PMinvoke
function in a companion object then, so that i can throw an Exception before instantiating the matrixkarelpeeters
05/05/2019, 9:28 PMDoubleArrayList
from here: https://korlibs.soywiz.com/kds/#ArrayListHullaballoonatic
05/05/2019, 9:29 PMkarelpeeters
05/05/2019, 9:29 PMHullaballoonatic
05/05/2019, 9:30 PMkarelpeeters
05/05/2019, 9:31 PMHullaballoonatic
05/05/2019, 9:32 PMkarelpeeters
05/05/2019, 9:32 PMHullaballoonatic
05/05/2019, 9:33 PMconstructor() { val thisOne: Foo }
karelpeeters
05/05/2019, 9:34 PMHullaballoonatic
05/05/2019, 9:41 PMcompanion object {
operator fun invoke(rows: List<List<Double>>): Matrix {
val width = rows[0].size
if (!rows.drop(1).all { it.size == width })
throw IllegalArgumentException("All rows must be of equal length.")
return Matrix(width, rows.flatten().toDoubleArray())
}
}
Wouldn't this assuredly prevent instantiation of the Matrix, and thus save time and memory?
I'm not sure how to perform actions in this order using normal constructorskarelpeeters
05/05/2019, 9:44 PMHullaballoonatic
05/05/2019, 9:45 PMkarelpeeters
05/05/2019, 9:46 PMclass Matrix(val width: Int, val height: Int, val content: DoubleArray)
fun Matrix(list: List<List<Double>>): Matrix {
//todo validation
return Matrix(list[0].size, list.size, list.flatten().toDoubleArray())
}
fun main() {
Matrix(2, 3, doubleArrayOf(.0, .0, .0, .0, .0, .0))
Matrix(listOf(listOf(.0, .0, .0), listOf(.0, .0, .0)))
}
Hullaballoonatic
05/05/2019, 9:49 PMkarelpeeters
05/05/2019, 9:50 PMHullaballoonatic
05/05/2019, 9:50 PM