Created
May 9, 2020 19:26
-
-
Save ygrenzinger/c487ce89f387045cceca3d61d1e32c8e to your computer and use it in GitHub Desktop.
Jetbrains academy Matrix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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