Minor refactoring + domains

This commit is contained in:
Alexander Nozik 2020-06-23 20:03:45 +03:00
parent 71846a3279
commit 668d13c9d1
13 changed files with 294 additions and 35 deletions

View File

@ -2,7 +2,7 @@ plugins {
id("scientifik.publish") apply false id("scientifik.publish") apply false
} }
val kmathVersion by extra("0.1.4-dev-7") val kmathVersion by extra("0.1.4-dev-8")
val bintrayRepo by extra("scientifik") val bintrayRepo by extra("scientifik")
val githubProject by extra("kmath") val githubProject by extra("kmath")

View File

@ -4,8 +4,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
java java
kotlin("jvm") kotlin("jvm")
kotlin("plugin.allopen") version "1.3.71" kotlin("plugin.allopen") version "1.3.72"
id("kotlinx.benchmark") version "0.2.0-dev-7" id("kotlinx.benchmark") version "0.2.0-dev-8"
} }
configure<AllOpenExtension> { configure<AllOpenExtension> {
@ -33,8 +33,8 @@ dependencies {
implementation(project(":kmath-dimensions")) implementation(project(":kmath-dimensions"))
implementation("com.kyonifer:koma-core-ejml:0.12") implementation("com.kyonifer:koma-core-ejml:0.12")
implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.2.0-npm-dev-6") implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.2.0-npm-dev-6")
implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-7") implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-8")
"benchmarksCompile"(sourceSets.main.get().compileClasspath) "benchmarksCompile"(sourceSets.main.get().output + sourceSets.main.get().compileClasspath) //sourceSets.main.output + sourceSets.main.runtimeClasspath
} }
// Configure benchmark // Configure benchmark

View File

@ -20,7 +20,7 @@ class ViktorBenchmark {
final val viktorField = ViktorNDField(intArrayOf(dim, dim)) final val viktorField = ViktorNDField(intArrayOf(dim, dim))
@Benchmark @Benchmark
fun `Automatic field addition`() { fun automaticFieldAddition() {
autoField.run { autoField.run {
var res = one var res = one
repeat(n) { repeat(n) {
@ -30,7 +30,7 @@ class ViktorBenchmark {
} }
@Benchmark @Benchmark
fun `Viktor field addition`() { fun viktorFieldAddition() {
viktorField.run { viktorField.run {
var res = one var res = one
repeat(n) { repeat(n) {
@ -40,7 +40,7 @@ class ViktorBenchmark {
} }
@Benchmark @Benchmark
fun `Raw Viktor`() { fun rawViktor() {
val one = F64Array.full(init = 1.0, shape = *intArrayOf(dim, dim)) val one = F64Array.full(init = 1.0, shape = *intArrayOf(dim, dim))
var res = one var res = one
repeat(n) { repeat(n) {
@ -49,7 +49,7 @@ class ViktorBenchmark {
} }
@Benchmark @Benchmark
fun `Real field log`() { fun realdFieldLog() {
realField.run { realField.run {
val fortyTwo = produce { 42.0 } val fortyTwo = produce { 42.0 }
var res = one var res = one
@ -61,7 +61,7 @@ class ViktorBenchmark {
} }
@Benchmark @Benchmark
fun `Raw Viktor log`() { fun rawViktorLog() {
val fortyTwo = F64Array.full(dim, dim, init = 42.0) val fortyTwo = F64Array.full(dim, dim, init = 42.0)
var res: F64Array var res: F64Array
repeat(n) { repeat(n) {

View File

@ -0,0 +1,38 @@
package scientifik.kmath.commons.random
import scientifik.kmath.prob.RandomGenerator
class CMRandomGeneratorWrapper(val factory: (IntArray) -> RandomGenerator) :
org.apache.commons.math3.random.RandomGenerator {
private var generator = factory(intArrayOf())
override fun nextBoolean(): Boolean = generator.nextBoolean()
override fun nextFloat(): Float = generator.nextDouble().toFloat()
override fun setSeed(seed: Int) {
generator = factory(intArrayOf(seed))
}
override fun setSeed(seed: IntArray) {
generator = factory(seed)
}
override fun setSeed(seed: Long) {
setSeed(seed.toInt())
}
override fun nextBytes(bytes: ByteArray) {
generator.fillBytes(bytes)
}
override fun nextInt(): Int = generator.nextInt()
override fun nextInt(n: Int): Int = generator.nextInt(n)
override fun nextGaussian(): Double = TODO()
override fun nextDouble(): Double = generator.nextDouble()
override fun nextLong(): Long = generator.nextLong()
}

View File

@ -0,0 +1,15 @@
package scientifik.kmath.domains
import scientifik.kmath.linear.Point
/**
* A simple geometric domain
*/
interface Domain<T : Any> {
operator fun contains(point: Point<T>): Boolean
/**
* Number of hyperspace dimensions
*/
val dimension: Int
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2015 Alexander Nozik.
*
* 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 scientifik.kmath.domains
import scientifik.kmath.linear.Point
import scientifik.kmath.structures.DoubleBuffer
import scientifik.kmath.structures.indices
/**
*
* HyperSquareDomain class.
*
* @author Alexander Nozik
*/
class HyperSquareDomain(private val lower: DoubleBuffer, private val upper: DoubleBuffer) : RealDomain {
override operator fun contains(point: Point<Double>): Boolean = point.indices.all { i ->
point[i] in lower[i]..upper[i]
}
override val dimension: Int get() = lower.size
override fun getLowerBound(num: Int, point: Point<Double>): Double? = lower[num]
override fun getLowerBound(num: Int): Double? = lower[num]
override fun getUpperBound(num: Int, point: Point<Double>): Double? = upper[num]
override fun getUpperBound(num: Int): Double? = upper[num]
override fun nearestInDomain(point: Point<Double>): Point<Double> {
val res: DoubleArray = DoubleArray(point.size) { i ->
when {
point[i] < lower[i] -> lower[i]
point[i] > upper[i] -> upper[i]
else -> point[i]
}
}
return DoubleBuffer(*res)
}
override fun volume(): Double {
var res = 1.0
for (i in 0 until dimension) {
if (lower[i].isInfinite() || upper[i].isInfinite()) {
return Double.POSITIVE_INFINITY
}
if (upper[i] > lower[i]) {
res *= upper[i] - lower[i]
}
}
return res
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2015 Alexander Nozik.
*
* 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 scientifik.kmath.domains
import scientifik.kmath.linear.Point
/**
* n-dimensional volume
*
* @author Alexander Nozik
*/
interface RealDomain: Domain<Double> {
fun nearestInDomain(point: Point<Double>): Point<Double>
/**
* The lower edge for the domain going down from point
* @param num
* @param point
* @return
*/
fun getLowerBound(num: Int, point: Point<Double>): Double?
/**
* The upper edge of the domain going up from point
* @param num
* @param point
* @return
*/
fun getUpperBound(num: Int, point: Point<Double>): Double?
/**
* Global lower edge
* @param num
* @return
*/
fun getLowerBound(num: Int): Double?
/**
* Global upper edge
* @param num
* @return
*/
fun getUpperBound(num: Int): Double?
/**
* Hyper volume
* @return
*/
fun volume(): Double
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2015 Alexander Nozik.
*
* 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 scientifik.kmath.domains
import scientifik.kmath.linear.Point
class UnconstrainedDomain(override val dimension: Int) : RealDomain {
override operator fun contains(point: Point<Double>): Boolean = true
override fun getLowerBound(num: Int, point: Point<Double>): Double? = Double.NEGATIVE_INFINITY
override fun getLowerBound(num: Int): Double? = Double.NEGATIVE_INFINITY
override fun getUpperBound(num: Int, point: Point<Double>): Double? = Double.POSITIVE_INFINITY
override fun getUpperBound(num: Int): Double? = Double.POSITIVE_INFINITY
override fun nearestInDomain(point: Point<Double>): Point<Double> = point
override fun volume(): Double = Double.POSITIVE_INFINITY
}

View File

@ -0,0 +1,48 @@
package scientifik.kmath.domains
import scientifik.kmath.linear.Point
import scientifik.kmath.structures.asBuffer
inline class UnivariateDomain(val range: ClosedFloatingPointRange<Double>) : RealDomain {
operator fun contains(d: Double): Boolean = range.contains(d)
override operator fun contains(point: Point<Double>): Boolean {
require(point.size == 0)
return contains(point[0])
}
override fun nearestInDomain(point: Point<Double>): Point<Double> {
require(point.size == 1)
val value = point[0]
return when{
value in range -> point
value >= range.endInclusive -> doubleArrayOf(range.endInclusive).asBuffer()
else -> doubleArrayOf(range.start).asBuffer()
}
}
override fun getLowerBound(num: Int, point: Point<Double>): Double? {
require(num == 0)
return range.start
}
override fun getUpperBound(num: Int, point: Point<Double>): Double? {
require(num == 0)
return range.endInclusive
}
override fun getLowerBound(num: Int): Double? {
require(num == 0)
return range.start
}
override fun getUpperBound(num: Int): Double? {
require(num == 0)
return range.endInclusive
}
override fun volume(): Double = range.endInclusive - range.start
override val dimension: Int get() = 1
}

View File

@ -12,26 +12,23 @@ import scientifik.kmath.structures.asBuffer
import scientifik.kmath.structures.asIterable import scientifik.kmath.structures.asIterable
import kotlin.math.sqrt import kotlin.math.sqrt
typealias RealPoint = Point<Double>
fun DoubleArray.asVector() = RealVector(this.asBuffer()) fun DoubleArray.asVector() = RealVector(this.asBuffer())
fun List<Double>.asVector() = RealVector(this.asBuffer()) fun List<Double>.asVector() = RealVector(this.asBuffer())
object VectorL2Norm : Norm<Point<out Number>, Double> { object VectorL2Norm : Norm<Point<out Number>, Double> {
override fun norm(arg: Point<out Number>): Double = sqrt(arg.asIterable().sumByDouble { it.toDouble() }) override fun norm(arg: Point<out Number>): Double = sqrt(arg.asIterable().sumByDouble { it.toDouble() })
} }
inline class RealVector(private val point: Point<Double>) : inline class RealVector(private val point: Point<Double>) :
SpaceElement<Point<Double>, RealVector, VectorSpace<Double, RealField>>, Point<Double> { SpaceElement<RealPoint, RealVector, VectorSpace<Double, RealField>>, RealPoint {
override val context: VectorSpace<Double, RealField> override val context: VectorSpace<Double, RealField> get() = space(point.size)
get() = space(
point.size
)
override fun unwrap(): Point<Double> = point override fun unwrap(): RealPoint = point
override fun Point<Double>.wrap(): RealVector = override fun RealPoint.wrap(): RealVector = RealVector(this)
RealVector(this)
override val size: Int get() = point.size override val size: Int get() = point.size
@ -48,12 +45,8 @@ inline class RealVector(private val point: Point<Double>) :
operator fun invoke(vararg values: Double): RealVector = values.asVector() operator fun invoke(vararg values: Double): RealVector = values.asVector()
fun space(dim: Int): BufferVectorSpace<Double, RealField> = fun space(dim: Int): BufferVectorSpace<Double, RealField> = spaceCache.getOrPut(dim) {
spaceCache.getOrPut(dim) { BufferVectorSpace(dim, RealField) { size, init -> Buffer.real(size, init) }
BufferVectorSpace(
dim,
RealField
) { size, init -> Buffer.real(size, init) }
} }
} }
} }

View File

@ -27,6 +27,10 @@ typealias RealMatrix = Matrix<Double>
fun realMatrix(rowNum: Int, colNum: Int, initializer: (i: Int, j: Int) -> Double): RealMatrix = fun realMatrix(rowNum: Int, colNum: Int, initializer: (i: Int, j: Int) -> Double): RealMatrix =
MatrixContext.real.produce(rowNum, colNum, initializer) MatrixContext.real.produce(rowNum, colNum, initializer)
fun Array<DoubleArray>.toMatrix(): RealMatrix{
return MatrixContext.real.produce(size, this[0].size) { row, col -> this[row][col] }
}
fun Sequence<DoubleArray>.toMatrix(): RealMatrix = toList().let { fun Sequence<DoubleArray>.toMatrix(): RealMatrix = toList().let {
MatrixContext.real.produce(it.size, it[0].size) { row, col -> it[row][col] } MatrixContext.real.produce(it.size, it[0].size) { row, col -> it[row][col] }
} }

View File

@ -1,18 +1,10 @@
package scientifik.kmath.histogram package scientifik.kmath.histogram
import scientifik.kmath.domains.Domain
import scientifik.kmath.linear.Point import scientifik.kmath.linear.Point
import scientifik.kmath.structures.ArrayBuffer import scientifik.kmath.structures.ArrayBuffer
import scientifik.kmath.structures.DoubleBuffer import scientifik.kmath.structures.DoubleBuffer
/**
* A simple geometric domain
* TODO move to geometry module
*/
interface Domain<T : Any> {
operator fun contains(vector: Point<out T>): Boolean
val dimension: Int
}
/** /**
* The bin in the histogram. The histogram is by definition always done in the real space * The bin in the histogram. The histogram is by definition always done in the real space
*/ */

View File

@ -10,6 +10,7 @@ interface MemorySpec<T : Any> {
val objectSize: Int val objectSize: Int
fun MemoryReader.read(offset: Int): T fun MemoryReader.read(offset: Int): T
//TODO consider thread safety
fun MemoryWriter.write(offset: Int, value: T) fun MemoryWriter.write(offset: Int, value: T)
} }