Skip to content

Instantly share code, notes, and snippets.

@ygrenzinger
Created May 9, 2020 19:26
Show Gist options
  • Save ygrenzinger/c487ce89f387045cceca3d61d1e32c8e to your computer and use it in GitHub Desktop.
Save ygrenzinger/c487ce89f387045cceca3d61d1e32c8e to your computer and use it in GitHub Desktop.
Jetbrains academy Matrix
package processor
import java.math.RoundingMode
import java.text.DecimalFormat
import java.text.NumberFormat
import java.util.*
import kotlin.math.pow
data class Matrix(val rowSize: Int, val columnSize: Int, val data: List<List<Double>>) {
operator fun plus(b: Matrix): Matrix {
val a = this
if (a.rowSize != b.rowSize || a.columnSize != b.columnSize) throw IllegalArgumentException("can't sum matrix of different dimensions")
val data = a.data.mapIndexed { i, row ->
row.mapIndexed { j, value ->
value + b.data[i][j]
}
}
return Matrix(rowSize, columnSize, data)
}
operator fun times(x: Int): Matrix {
val data = this.data.map { row ->
row.map { value ->
value * x
}
}
return Matrix(rowSize, columnSize, data)
}
operator fun times(b: Matrix): Matrix {
val a = this
if (a.columnSize != b.rowSize) throw IllegalArgumentException("can't multiply matrices")
val data =
(0 until a.rowSize).map { ai ->
(0 until b.columnSize).map { bj ->
(0 until a.columnSize).map { i ->
a.data[ai][i] * b.data[i][bj]
}.sum()
}
}
return Matrix(rowSize, columnSize, data)
}
fun display() {
val locale = Locale("en", "US")
val decimalFormat = NumberFormat.getNumberInstance(locale) as DecimalFormat
decimalFormat.applyPattern("###########.####")
decimalFormat.roundingMode = RoundingMode.DOWN
data.forEach { row ->
println(row.joinToString(" "))
}
}
fun transposeMainDiagonal(): Matrix {
return Matrix(columnSize, rowSize, recursiveTransposeMainDiagonal(data))
}
fun transposeSideDiagonal(): Matrix {
return data.map { it.reversed() }.reversed().let {
recursiveTransposeMainDiagonal(it)
}.let {
Matrix(columnSize, rowSize, it)
}
}
private fun recursiveTransposeMainDiagonal(data: List<List<Double>>): List<List<Double>> {
val heads = data.flatMap { it.take(1) }
val tails = data.map { it.drop(1) }
return if (heads.isEmpty()) {
listOf()
} else {
listOf(heads) + recursiveTransposeMainDiagonal(tails)
}
}
fun transposeVerticalLine(): Matrix {
return this.copy(data = data.map { it.reversed() })
}
fun transposeHorizontalLine(): Matrix {
return this.copy(data = data.reversed())
}
fun determinant(): Double {
if (rowSize != columnSize) throw throw IllegalArgumentException("Must be square to calculate determinant")
return determinant(data)
}
fun inverse(): Matrix {
val det = this.determinant()
if (det == 0.0) throw IllegalArgumentException("there is no determinant")
val range = (data.indices)
val data = range.map { i ->
range.map { j ->
val value = (1.0 / det) * computeCofactor(data, i, j)
if (value == -0.0) 0.0 else value
}
}
return Matrix(rowSize, columnSize, data).transposeMainDiagonal()
}
companion object {
private fun determinant(data: List<List<Double>>): Double {
if (data.size == 1) return data[0][0]
if (data.size == 2) return data[0][0] * data[1][1] - data[0][1] * data[1][0]
val i = data
.mapIndexed { i, row -> Pair(i, row.count { it == 0.0 }) }
.maxBy { it.second }!!
.first
return (data.indices).map { j ->
if (data[i][j] == 0.0) {
0.0
} else {
data[i][j] * computeCofactor(data, i, j)
}
}.sum()
}
private fun computeCofactor(data: List<List<Double>>, i: Int, j: Int): Double {
val minor = determinant(submatrix(data, i, j))
return (-1.0).pow((i + 1) + (j + 1)) * minor
}
private fun submatrix(data: List<List<Double>>, i: Int, j: Int) =
(removeAtIndex(data, i)).map { removeAtIndex(it, j) }
private fun <T> removeAtIndex(list: List<T>, i: Int) =
list.subList(0, i) + list.subList(i + 1, list.size)
private fun <T> Scanner.read(convert: (String) -> T) = this.nextLine().trim().split(" ").map(convert)
fun fromScanner(name: String, scanner: Scanner): Matrix {
print("Enter size of $name matrix: ")
val sizes = scanner.read { it.toInt() }
println("Enter $name matrix:")
val data = (1..sizes[0]).map {
scanner.read { it.toDouble() }
}
if (data.size != sizes[0] || data.any { it.size != sizes[1] }) {
throw IllegalArgumentException("Wrong input")
}
return Matrix(sizes[0], sizes[1], data)
}
}
}
fun main() {
val scanner = Scanner(System.`in`)
var choice = menu(scanner)
while (choice != 0) {
try {
when (choice) {
1 -> matrixAddition(scanner)
2 -> matrixTimesConstant(scanner)
3 -> matrixMultiplication(scanner)
4 -> transposeMatrix(scanner)
5 -> calculateDeterminant(scanner)
6 -> inverseMatrix(scanner)
}
} catch (ex: IllegalArgumentException) {
println("ERROR")
}
choice = menu(scanner)
}
}
private fun menu(scanner: Scanner): Int {
println("""
1. Add matrices
2. Multiply matrix to a constant
3. Multiply matrices
4. Transpose matrix
5. Calculate a determinant
6. Inverse matrix
0. Exit
""".trimIndent())
print("Your choice: ")
return scanner.nextLine().toInt()
}
fun inverseMatrix(scanner: Scanner) {
val matrix = Matrix.fromScanner("", scanner)
val result = matrix.inverse()
println("The result is:")
result.display()
}
fun calculateDeterminant(scanner: Scanner) {
val matrix = Matrix.fromScanner("", scanner)
val result = matrix.determinant()
println("The result is:")
println(result)
}
fun transposeMatrix(scanner: Scanner) {
println("""
1. Main diagonal
2. Side diagonal
3. Vertical line
4. Horizontal line
""".trimIndent())
print("Your choice: ")
val choice = scanner.nextLine().toInt()
val matrix = Matrix.fromScanner("", scanner)
when (choice) {
1 -> matrix.transposeMainDiagonal().display()
2 -> matrix.transposeSideDiagonal().display()
3 -> matrix.transposeVerticalLine().display()
4 -> matrix.transposeHorizontalLine().display()
}
}
private fun matrixMultiplication(scanner: Scanner) {
val a = Matrix.fromScanner("first", scanner)
val b = Matrix.fromScanner("second", scanner)
val result = a * b
println("The multiplication result is:")
result.display()
}
private fun matrixTimesConstant(scanner: Scanner) {
val a = Matrix.fromScanner("first", scanner)
print("Enter constant")
val x = scanner.nextLine().toInt()
val result = a * x
println("The multiplication result is:")
result.display()
}
private fun matrixAddition(scanner: Scanner) {
val a = Matrix.fromScanner("first", scanner)
val b = Matrix.fromScanner("second", scanner)
val result = a + b
println("The multiplication addition is:")
result.display()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment