mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-09 18:14:06 +09:00
always sorting arraylist; more wire stuffs
This commit is contained in:
134
src/net/torvald/util/ArrayListMap.kt
Normal file
134
src/net/torvald/util/ArrayListMap.kt
Normal file
@@ -0,0 +1,134 @@
|
||||
package net.torvald.util
|
||||
|
||||
import java.util.function.BiConsumer
|
||||
import java.util.function.BiFunction
|
||||
import java.util.function.Function
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-07-15.
|
||||
*/
|
||||
class ArrayListMap<K, V> : MutableMap<K, V> {
|
||||
|
||||
private val keysArray = ArrayList<K>()
|
||||
private val valuesArray = ArrayList<V>()
|
||||
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
|
||||
|
||||
override val size: Int
|
||||
get() = keysArray.size
|
||||
|
||||
override val values: MutableCollection<V>
|
||||
get() = valuesArray.toMutableSet()
|
||||
|
||||
override val keys: MutableSet<K>
|
||||
get() = keysArray.toMutableSet()
|
||||
|
||||
|
||||
|
||||
override fun containsKey(key: K): Boolean {
|
||||
return keysArray.contains(key)
|
||||
}
|
||||
|
||||
override fun containsValue(value: V): Boolean {
|
||||
return valuesArray.contains(value)
|
||||
}
|
||||
|
||||
override fun forEach(action: BiConsumer<in K, in V>) {
|
||||
for (i in 0 until size) {
|
||||
action.accept(keysArray[i], valuesArray[i])
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(key: K): V? {
|
||||
val index = keysArray.linearSearch(key)
|
||||
index?.let {
|
||||
return valuesArray[index]
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getOrDefault(key: K, defaultValue: V): V {
|
||||
return get(key) ?: defaultValue
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return size == 0
|
||||
}
|
||||
|
||||
|
||||
private fun ArrayList<K>.linearSearch(element: K): Int? {
|
||||
var found = 0
|
||||
while (found < keysArray.size) {
|
||||
if (keysArray[found] == element)
|
||||
return found
|
||||
|
||||
found++
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun put(key: K, value: V): V? {
|
||||
val index = keysArray.linearSearch(key)
|
||||
if (index != null) {
|
||||
val oldValue = valuesArray[index]
|
||||
valuesArray[index] = value
|
||||
return oldValue
|
||||
}
|
||||
else {
|
||||
keysArray.add(key)
|
||||
valuesArray.add(value)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun compute(key: K, remappingFunction: BiFunction<in K, in V?, out V?>): V? {
|
||||
return super.compute(key, remappingFunction)
|
||||
}
|
||||
|
||||
override fun computeIfAbsent(key: K, mappingFunction: Function<in K, out V>): V {
|
||||
return super.computeIfAbsent(key, mappingFunction)
|
||||
}
|
||||
|
||||
override fun computeIfPresent(key: K, remappingFunction: BiFunction<in K, in V, out V?>): V? {
|
||||
return super.computeIfPresent(key, remappingFunction)
|
||||
}
|
||||
|
||||
override fun merge(key: K, value: V, remappingFunction: BiFunction<in V, in V, out V?>): V? {
|
||||
return super.merge(key, value, remappingFunction)
|
||||
}
|
||||
|
||||
override fun putAll(from: Map<out K, V>) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun putIfAbsent(key: K, value: V): V? {
|
||||
return super.putIfAbsent(key, value)
|
||||
}
|
||||
|
||||
override fun remove(key: K): V? {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun remove(key: K, value: V): Boolean {
|
||||
return super.remove(key, value)
|
||||
}
|
||||
|
||||
override fun replace(key: K, oldValue: V, newValue: V): Boolean {
|
||||
return super.replace(key, oldValue, newValue)
|
||||
}
|
||||
|
||||
override fun replace(key: K, value: V): V? {
|
||||
return super.replace(key, value)
|
||||
}
|
||||
|
||||
override fun replaceAll(function: BiFunction<in K, in V, out V>) {
|
||||
super.replaceAll(function)
|
||||
}
|
||||
|
||||
}
|
||||
82
src/net/torvald/util/CircularArray.kt
Normal file
82
src/net/torvald/util/CircularArray.kt
Normal file
@@ -0,0 +1,82 @@
|
||||
package net.torvald.util
|
||||
|
||||
|
||||
/**
|
||||
* buffer[head] contains the most recent item, whereas buffer[tail] contains the oldest one.
|
||||
*
|
||||
* Notes for particle storage:
|
||||
* Particles does not need to be removed, just let it overwrite as their operation is rather
|
||||
* lightweight. So, just flagDespawn = true if it need to be "deleted" so that it won't update
|
||||
* anymore.
|
||||
*
|
||||
* Created by minjaesong on 2017-01-22.
|
||||
*/
|
||||
class CircularArray<T>(val size: Int) {
|
||||
|
||||
val buffer: Array<T> = arrayOfNulls<Any>(size) as Array<T>
|
||||
var tail: Int = 0; private set
|
||||
var head: Int = -1; private set
|
||||
|
||||
private var unreliableAddCount = 0
|
||||
|
||||
val lastIndex = size - 1
|
||||
|
||||
/**
|
||||
* Number of elements that forEach() or fold() would iterate.
|
||||
*/
|
||||
val elemCount: Int
|
||||
get() = minOf(unreliableAddCount, size)
|
||||
|
||||
fun add(item: T) {
|
||||
if (unreliableAddCount <= size) unreliableAddCount += 1
|
||||
|
||||
head = (head + 1) % size
|
||||
if (unreliableAddCount > size) {
|
||||
tail = (tail + 1) % size
|
||||
}
|
||||
|
||||
buffer[head] = item // overwrites oldest item when eligible
|
||||
|
||||
|
||||
//println("$this $unreliableAddCount")
|
||||
}
|
||||
|
||||
fun getHeadElem(): T = buffer[head]
|
||||
fun getTailElem(): T = buffer[tail]
|
||||
|
||||
/**
|
||||
* Iterates the array with oldest element first.
|
||||
*/
|
||||
fun forEach(action: (T) -> Unit) {
|
||||
// has slightly better iteration performance than lambda
|
||||
if (unreliableAddCount <= size) {
|
||||
for (i in 0..head)
|
||||
action(buffer[i])
|
||||
}
|
||||
else {
|
||||
for (i in 0..size - 1)
|
||||
action(buffer[(i + tail) % size])
|
||||
}
|
||||
}
|
||||
|
||||
fun <R> fold(initial: R, operation: (R, T) -> R): R {
|
||||
var accumulator = initial
|
||||
//for (element in buffer) accumulator = operation(accumulator, element)
|
||||
if (unreliableAddCount <= size) {
|
||||
for (i in 0..head)
|
||||
accumulator = operation(accumulator, buffer[i])
|
||||
}
|
||||
else {
|
||||
for (i in 0..size - 1)
|
||||
accumulator = operation(accumulator, buffer[(i + tail) % size])
|
||||
}
|
||||
|
||||
return accumulator
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "CircularArray(size=" + buffer.size + ", head=" + head + ", tail=" + tail + ")"
|
||||
}
|
||||
}
|
||||
97
src/net/torvald/util/Float16.kt
Normal file
97
src/net/torvald/util/Float16.kt
Normal file
@@ -0,0 +1,97 @@
|
||||
package net.torvald.util
|
||||
|
||||
import kotlin.experimental.or
|
||||
|
||||
/**
|
||||
* https://stackoverflow.com/questions/6162651/half-precision-floating-point-in-java#6162687
|
||||
*
|
||||
* Created by minjaesong on 2017-04-21.
|
||||
*/
|
||||
typealias Float16Bits = Short
|
||||
|
||||
class Float16() {
|
||||
|
||||
var bits = 0.toShort()
|
||||
private set
|
||||
|
||||
constructor(fval: Float) : this() {
|
||||
fromFloat(fval)
|
||||
}
|
||||
|
||||
fun toFloat() = Float16.toFloat(bits)
|
||||
fun fromFloat(fval: Float) {
|
||||
bits = Float16.fromFloat(fval)
|
||||
}
|
||||
|
||||
|
||||
operator fun times(other: Float) = fromFloat(this.toFloat() * other)
|
||||
operator fun times(other: Float16) = fromFloat(this.toFloat() * other.toFloat())
|
||||
|
||||
operator fun div(other: Float) = fromFloat(this.toFloat() / other)
|
||||
operator fun div(other: Float16) = fromFloat(this.toFloat() / other.toFloat())
|
||||
|
||||
// operators are stripped: you don't calculate from FP16; this is only for storing values //
|
||||
|
||||
companion object {
|
||||
fun toFloat(hbits: Short): Float {
|
||||
val hbits = hbits.toInt().and(0xFFFF)
|
||||
|
||||
var mant = hbits and 0x03ff // 10 bits mantissa
|
||||
var exp = hbits and 0x7c00 // 5 bits exponent
|
||||
if (exp == 0x7c00)
|
||||
// NaN/Inf
|
||||
exp = 0x3fc00 // -> NaN/Inf
|
||||
else if (exp != 0)
|
||||
// normalized value
|
||||
{
|
||||
exp += 0x1c000 // exp - 15 + 127
|
||||
if (mant == 0 && exp > 0x1c400)
|
||||
// smooth transition
|
||||
return java.lang.Float.intBitsToFloat(hbits and 0x8000 shl 16 or (exp shl 13) or 0x3ff)
|
||||
}
|
||||
else if (mant != 0)
|
||||
// && exp==0 -> subnormal
|
||||
{
|
||||
exp = 0x1c400 // make it normal
|
||||
do {
|
||||
mant = mant shl 1 // mantissa * 2
|
||||
exp -= 0x400 // decrease exp by 1
|
||||
} while (mant and 0x400 == 0) // while not normal
|
||||
mant = mant and 0x3ff // discard subnormal bit
|
||||
} // else +/-0 -> +/-0
|
||||
return java.lang.Float.intBitsToFloat(// combine all parts
|
||||
hbits and 0x8000 shl 16 or (exp or mant shl 13)) // value << ( 23 - 10 )
|
||||
}
|
||||
|
||||
fun fromFloat(fval: Float): Short {
|
||||
val fbits = java.lang.Float.floatToIntBits(fval)
|
||||
val sign = fbits.ushr(16).and(0x8000).toShort() // sign only
|
||||
var `val` = (fbits and 0x7fffffff) + 0x1000 // rounded value
|
||||
|
||||
if (`val` >= 0x47800000)
|
||||
// might be or become NaN/Inf
|
||||
{ // avoid Inf due to rounding
|
||||
if (fbits and 0x7fffffff >= 0x47800000) { // is or must become NaN/Inf
|
||||
if (`val` < 0x7f800000)
|
||||
// was value but too large
|
||||
return sign or 0x7c00 // make it +/-Inf
|
||||
return sign or 0x7c00 or // remains +/-Inf or NaN
|
||||
(fbits and 0x007fffff).ushr(13).toShort() // keep NaN (and Inf) bits
|
||||
}
|
||||
return sign or 0x7bff.toShort() // unrounded not quite Inf
|
||||
}
|
||||
if (`val` >= 0x38800000)
|
||||
// remains normalized value
|
||||
return sign or (`val` - 0x38000000).ushr(13).toShort() // exp - 127 + 15
|
||||
if (`val` < 0x33000000)
|
||||
// too small for subnormal
|
||||
return sign // becomes +/-0
|
||||
`val` = (fbits and 0x7fffffff).ushr(23) // tmp exp for subnormal calc
|
||||
|
||||
return sign or ((fbits and 0x7fffff or 0x800000) // add subnormal bit
|
||||
+ 0x800000.ushr(`val` - 102) // round depending on cut off
|
||||
).ushr(126 - `val`) // div by 2^(1-(exp-127+15)) and >> 13 | exp=0
|
||||
.toShort()
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/net/torvald/util/HistoryArray.kt
Normal file
66
src/net/torvald/util/HistoryArray.kt
Normal file
@@ -0,0 +1,66 @@
|
||||
package net.torvald.util
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Simple ArrayList wrapper that acts as history keeper. You can append any data but cannot delete.
|
||||
*
|
||||
* Created by minjaesong on 2016-07-13.
|
||||
*/
|
||||
class HistoryArray<T>(val size: Int) {
|
||||
|
||||
val history = ArrayList<T?>(Math.min(size, 256)) // 256: arbitrary set upper bound
|
||||
|
||||
val lastIndex = size - 1
|
||||
|
||||
val elemCount: Int
|
||||
get() = history.size
|
||||
|
||||
fun add(value: T) {
|
||||
if (history.size == 0) {
|
||||
history.add(value)
|
||||
return
|
||||
}
|
||||
// push existing values to an index
|
||||
else {
|
||||
for (i in history.size - 1 downTo 0) {
|
||||
// if history.size is smaller than 'size', make room by appending
|
||||
if (i == history.size - 1 && i < size - 1)
|
||||
history.add(history[i])
|
||||
// actually move if we have some room
|
||||
else if (i < size - 1)
|
||||
history[i + 1] = history[i]
|
||||
}
|
||||
}
|
||||
// add new value to the room
|
||||
history[0] = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Get certain index from history. NOTE: index 0 means latest!
|
||||
*/
|
||||
operator fun get(index: Int): T? =
|
||||
if (index >= history.size) null
|
||||
else history[index]
|
||||
|
||||
/**
|
||||
* Iterate from latest to oldest
|
||||
*/
|
||||
fun iterator() = history.iterator()
|
||||
|
||||
/**
|
||||
* Iterate from latest to oldest
|
||||
*/
|
||||
fun forEach(action: (T?) -> Unit) = history.forEach(action)
|
||||
|
||||
val latest: T?
|
||||
get() = this[0]
|
||||
|
||||
val oldest: T?
|
||||
get() = this[history.size - 1]
|
||||
|
||||
fun clear() {
|
||||
history.clear()
|
||||
}
|
||||
|
||||
}
|
||||
100
src/net/torvald/util/IntArrayStack.kt
Normal file
100
src/net/torvald/util/IntArrayStack.kt
Normal file
@@ -0,0 +1,100 @@
|
||||
package net.torvald.util
|
||||
|
||||
import java.util.*
|
||||
|
||||
class IntArrayStack {
|
||||
/**
|
||||
* Number of elements in the stack
|
||||
*/
|
||||
var depth: Int = 0
|
||||
private set
|
||||
|
||||
var size: Int
|
||||
get() = data.size
|
||||
set(newSize) {
|
||||
if (newSize > depth) inflate(newSize - data.size)
|
||||
else deflate(data.size - newSize)
|
||||
}
|
||||
|
||||
private lateinit var data: IntArray
|
||||
|
||||
constructor(stackSize: Int) {
|
||||
data = IntArray(stackSize)
|
||||
}
|
||||
|
||||
constructor(arr: IntArray) {
|
||||
data = arr.copyOf()
|
||||
depth = size
|
||||
}
|
||||
|
||||
fun push(v: Int) {
|
||||
if (depth >= data.size) throw StackOverflowError()
|
||||
data[depth++] = v
|
||||
}
|
||||
|
||||
fun pop(): Int {
|
||||
if (depth == 0) throw EmptyStackException()
|
||||
return data[--depth]
|
||||
}
|
||||
|
||||
fun peek(): Int? {
|
||||
if (depth == 0) return null
|
||||
return data[depth - 1]
|
||||
}
|
||||
|
||||
fun dup() {
|
||||
if (depth == 0) throw EmptyStackException()
|
||||
if (depth == data.size) throw StackOverflowError()
|
||||
push(peek()!!)
|
||||
}
|
||||
|
||||
fun swap() {
|
||||
if (depth < 2) throw UnsupportedOperationException("Stack is empty or has only one element.")
|
||||
val up = pop()
|
||||
val dn = pop()
|
||||
push(up)
|
||||
push(dn)
|
||||
}
|
||||
|
||||
fun drop() {
|
||||
if (depth == 0) throw EmptyStackException()
|
||||
--depth
|
||||
}
|
||||
|
||||
fun defineFromArray(arr: IntArray) { data = arr.copyOf() }
|
||||
|
||||
/**
|
||||
* Increase the stack size by a factor.
|
||||
*/
|
||||
fun inflate(sizeToAdd: Int) {
|
||||
if (sizeToAdd < 0) throw UnsupportedOperationException("$sizeToAdd: Cannot deflate the stack with this function. Use deflate(int) instead.")
|
||||
size += sizeToAdd
|
||||
val oldStack = this.asArray()
|
||||
data = IntArray(size, { if (it < oldStack.size) oldStack[it] else 0 })
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease the stack size by a factor. Overflowing data will be removed.
|
||||
*/
|
||||
fun deflate(sizeToTake: Int) {
|
||||
if (size - sizeToTake < 1) throw UnsupportedOperationException("$sizeToTake: Cannot deflate the stack to the size of zero or negative.")
|
||||
size -= sizeToTake
|
||||
val oldStack = this.asArray()
|
||||
data = IntArray(size, { oldStack[it] })
|
||||
if (depth > data.size) depth = data.size
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert stack as array. Index zero is the bottommost element.
|
||||
* @return array of data, with array size equivalent to the stack depth.
|
||||
*/
|
||||
fun asArray() = data.copyOfRange(0, depth - 1)
|
||||
|
||||
fun equalTo(other: IntArrayStack) = (this.asArray() == other.asArray())
|
||||
|
||||
fun plus() { data[depth - 2] += pop() }
|
||||
fun minus() { data[depth - 2] -= pop() }
|
||||
fun times() { data[depth - 2] *= pop() }
|
||||
fun div() { data[depth - 2] /= pop() }
|
||||
fun mod() { data[depth - 2] %= pop() }
|
||||
}
|
||||
171
src/net/torvald/util/Matrix.kt
Normal file
171
src/net/torvald/util/Matrix.kt
Normal file
@@ -0,0 +1,171 @@
|
||||
package net.torvald.util
|
||||
|
||||
/**
|
||||
* Taken and improved from https://introcs.cs.princeton.edu/java/95linear/Matrix.java.html
|
||||
*
|
||||
* Created by minjaesong on 2018-08-01.
|
||||
*/
|
||||
class Matrix {
|
||||
val rows: Int // number of rows; M
|
||||
val cols: Int // number of columns; N
|
||||
val data: Array<DoubleArray> // M-by-N array
|
||||
|
||||
// create M-by-N matrix of 0's
|
||||
constructor(M: Int, N: Int) {
|
||||
this.rows = M
|
||||
this.cols = N
|
||||
data = Array(M) { DoubleArray(N) }
|
||||
}
|
||||
|
||||
// create matrix based on 2d array
|
||||
constructor(data: Array<DoubleArray>) {
|
||||
rows = data.size
|
||||
cols = data[0].size
|
||||
this.data = Array(rows) { DoubleArray(cols) }
|
||||
for (i in 0 until rows)
|
||||
for (j in 0 until cols)
|
||||
this.data[i][j] = data[i][j]
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
private constructor(A: Matrix) : this(A.data) {}
|
||||
|
||||
// swap rows i and j
|
||||
private fun swap(i: Int, j: Int) {
|
||||
val temp = data[i]
|
||||
data[i] = data[j]
|
||||
data[j] = temp
|
||||
}
|
||||
|
||||
// create and return the transpose of the invoking matrix
|
||||
fun transpose(): Matrix {
|
||||
val A = Matrix(cols, rows)
|
||||
for (i in 0 until rows)
|
||||
for (j in 0 until cols)
|
||||
A.data[j][i] = this.data[i][j]
|
||||
return A
|
||||
}
|
||||
|
||||
// return C = A + B
|
||||
operator fun plus(B: Matrix): Matrix {
|
||||
val A = this
|
||||
if (B.rows != A.rows || B.cols != A.cols) throw RuntimeException("Illegal matrix dimensions.")
|
||||
val C = Matrix(rows, cols)
|
||||
for (i in 0 until rows)
|
||||
for (j in 0 until cols)
|
||||
C.data[i][j] = A.data[i][j] + B.data[i][j]
|
||||
return C
|
||||
}
|
||||
|
||||
|
||||
// return C = A - B
|
||||
operator fun minus(B: Matrix): Matrix {
|
||||
val A = this
|
||||
if (B.rows != A.rows || B.cols != A.cols) throw RuntimeException("Illegal matrix dimensions.")
|
||||
val C = Matrix(rows, cols)
|
||||
for (i in 0 until rows)
|
||||
for (j in 0 until cols)
|
||||
C.data[i][j] = A.data[i][j] - B.data[i][j]
|
||||
return C
|
||||
}
|
||||
|
||||
// does A = B exactly?
|
||||
override fun equals(B: Any?): Boolean {
|
||||
if (B !is Matrix) throw RuntimeException("Not a Matrix.")
|
||||
|
||||
val A = this
|
||||
if (B.rows != A.rows || B.cols != A.cols) throw RuntimeException("Illegal matrix dimensions.")
|
||||
for (i in 0 until rows)
|
||||
for (j in 0 until cols)
|
||||
if (A.data[i][j] != B.data[i][j]) return false
|
||||
return true
|
||||
}
|
||||
|
||||
// return C = A * B
|
||||
operator fun times(B: Matrix): Matrix {
|
||||
val A = this
|
||||
if (A.cols != B.rows) throw RuntimeException("Illegal matrix dimensions.")
|
||||
val C = Matrix(A.rows, B.cols)
|
||||
for (i in 0 until C.rows)
|
||||
for (j in 0 until C.cols)
|
||||
for (k in 0 until A.cols)
|
||||
C.data[i][j] += A.data[i][k] * B.data[k][j]
|
||||
return C
|
||||
}
|
||||
|
||||
|
||||
// return x = A^-1 b, assuming A is square and has full rank
|
||||
fun solve(rhs: Matrix): Matrix {
|
||||
if (rows != cols || rhs.rows != cols || rhs.cols != 1)
|
||||
throw RuntimeException("Illegal matrix dimensions.")
|
||||
|
||||
// create copies of the data
|
||||
val A = Matrix(this)
|
||||
val b = Matrix(rhs)
|
||||
|
||||
// Gaussian elimination with partial pivoting
|
||||
for (i in 0 until cols) {
|
||||
|
||||
// find pivot row and swap
|
||||
var max = i
|
||||
for (j in i + 1 until cols)
|
||||
if (Math.abs(A.data[j][i]) > Math.abs(A.data[max][i]))
|
||||
max = j
|
||||
A.swap(i, max)
|
||||
b.swap(i, max)
|
||||
|
||||
// singular
|
||||
if (A.data[i][i] == 0.0) throw RuntimeException("Matrix is singular.")
|
||||
|
||||
// pivot within b
|
||||
for (j in i + 1 until cols)
|
||||
b.data[j][0] -= b.data[i][0] * A.data[j][i] / A.data[i][i]
|
||||
|
||||
// pivot within A
|
||||
for (j in i + 1 until cols) {
|
||||
val m = A.data[j][i] / A.data[i][i]
|
||||
for (k in i + 1 until cols) {
|
||||
A.data[j][k] -= A.data[i][k] * m
|
||||
}
|
||||
A.data[j][i] = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
// back substitution
|
||||
val x = Matrix(cols, 1)
|
||||
for (j in cols - 1 downTo 0) {
|
||||
var t = 0.0
|
||||
for (k in j + 1 until cols)
|
||||
t += A.data[j][k] * x.data[k][0]
|
||||
x.data[j][0] = (b.data[j][0] - t) / A.data[j][j]
|
||||
}
|
||||
return x
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* for idioms of ```element = mat[row][column]```
|
||||
*/
|
||||
operator fun get(i: Int): DoubleArray = data[i]
|
||||
|
||||
companion object {
|
||||
|
||||
// create and return a random M-by-N matrix with values between 0 and 1
|
||||
fun random(M: Int, N: Int): Matrix {
|
||||
val A = Matrix(M, N)
|
||||
for (i in 0 until M)
|
||||
for (j in 0 until N)
|
||||
A.data[i][j] = Math.random()
|
||||
return A
|
||||
}
|
||||
|
||||
// create and return the N-by-N identity matrix
|
||||
fun identity(N: Int): Matrix {
|
||||
val I = Matrix(N, N)
|
||||
for (i in 0 until N)
|
||||
I.data[i][i] = 1.0
|
||||
return I
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
86
src/net/torvald/util/SortedArrayList.kt
Normal file
86
src/net/torvald/util/SortedArrayList.kt
Normal file
@@ -0,0 +1,86 @@
|
||||
package net.torvald.util
|
||||
|
||||
import net.torvald.terrarum.lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
/**
|
||||
* The modification of the arraylist that its element is always sorted.
|
||||
*
|
||||
* Created by minjaesong on 2019-03-12.
|
||||
*/
|
||||
class SortedArrayList<T: Comparable<T>>(initialSize: Int = 10) {
|
||||
|
||||
private val arrayList = ArrayList<T>(initialSize)
|
||||
|
||||
/**
|
||||
*/
|
||||
fun add(elem: T) {
|
||||
// don't append-at-tail-and-sort; just insert at right index
|
||||
ReentrantLock().lock {
|
||||
var low = 0
|
||||
var high = arrayList.size
|
||||
|
||||
while (low < high) {
|
||||
val mid = (low + high).ushr(1)
|
||||
|
||||
if (arrayList[mid] > elem)
|
||||
high = mid
|
||||
else
|
||||
low = mid + 1
|
||||
}
|
||||
|
||||
arrayList.add(low, elem)
|
||||
}
|
||||
}
|
||||
|
||||
val size: Int
|
||||
get() = arrayList.size
|
||||
|
||||
fun removeAt(index: Int) = arrayList.removeAt(index)
|
||||
fun remove(element: T) = arrayList.remove(element)
|
||||
fun removeLast() = arrayList.removeAt(arrayList.size)
|
||||
|
||||
operator fun get(index: Int) = arrayList[index]
|
||||
|
||||
fun iterator() = arrayList.iterator()
|
||||
fun forEach(action: (T) -> Unit) = arrayList.forEach(action)
|
||||
fun forEachIndexed(action: (Int, T) -> Unit) = arrayList.forEachIndexed(action)
|
||||
//fun <R> map(transformation: (T) -> R) = arrayList.map(transformation)
|
||||
|
||||
/**
|
||||
* Select one unsorted element from the array and put it onto the sorted spot.
|
||||
*
|
||||
* The list must be fully sorted except for that one "renegade", otherwise the operation is undefined behaviour.
|
||||
*/
|
||||
private fun sortThisRenegade(index: Int) {
|
||||
if (
|
||||
(index == arrayList.lastIndex && arrayList[index - 1] <= arrayList[index]) ||
|
||||
(index == 0 && arrayList[index] <= arrayList[index + 1]) ||
|
||||
(arrayList[index - 1] <= arrayList[index] && arrayList[index] <= arrayList[index + 1])
|
||||
) return
|
||||
|
||||
// modified binary search
|
||||
ReentrantLock().lock {
|
||||
val renegade = arrayList.removeAt(index)
|
||||
|
||||
var low = 0
|
||||
var high = arrayList.size
|
||||
|
||||
while (low < high) {
|
||||
val mid = (low + high).ushr(1)
|
||||
|
||||
if (arrayList[mid] > renegade)
|
||||
high = mid
|
||||
else
|
||||
low = mid + 1
|
||||
}
|
||||
|
||||
arrayList.add(low, renegade)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does NOT create copies!
|
||||
*/
|
||||
fun toArrayList() = arrayList
|
||||
}
|
||||
Reference in New Issue
Block a user