Fully refactor algebra split ScaleOperations from Space. #219

Merged
altavir merged 6 commits from refactor/algebra-scale into dev 2021-03-11 11:28:54 +03:00
62 changed files with 869 additions and 1096 deletions
Showing only changes of commit 8ae8ebe871 - Show all commits

View File

@ -1,6 +1,5 @@
# Based on https://github.com/touchlab/Stately/blob/main/.github/workflows/build.yml
name: Gradle build
name: build
on: [ push ]
jobs:

View File

@ -1,10 +1,15 @@
# Based on https://github.com/touchlab/Stately/blob/main/.github/workflows/deploy.yml
name: Gradle publish
name: deploy
on: workflow_dispatch
on:
workflow_dispatch:
release:
types:
- created
jobs:
build:
publish:
environment:
name: publish
strategy:
matrix:
os: [macOS-latest, windows-latest]
@ -33,13 +38,22 @@ jobs:
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Publish Mac Artifacts
if: matrix.os == 'macOS-latest'
run: ./gradlew publishAllPublicationsToSpaceRepository publishAllPublicationsToSonatypeRepository --no-daemon --stacktrace -PsonatypePublish=true -PsonatypeUser=${{ secrets.SONATYPE_USERNAME }} -PsonatypePassword=${{ secrets.SONATYPE_PASSWORD }} -PspaceUser=${{ secrets.SPACE_USERNAME }} -PspacePassword=${{ secrets.SPACE_PASSWORD }}
env:
signingKey: ${{ secrets.SIGNING_KEY }}
- name: Publish Windows Artifacts
if: matrix.os == 'windows-latest'
run: ./gradlew publishAllPublicationsToSpaceRepository publishAllPublicationsToSonatypeRepository --no-daemon --stacktrace -PsonatypePublish=true -PsonatypeUser=${{ secrets.SONATYPE_USERNAME }} -PsonatypePassword=${{ secrets.SONATYPE_PASSWORD }} -PspaceUser=${{ secrets.SPACE_USERNAME }} -PspacePassword=${{ secrets.SPACE_PASSWORD }}
env:
signingKey: ${{ secrets.SIGNING_KEY }}
run: >
./gradlew release --no-daemon
-Ppublishing.enabled=true
-Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }}
-Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }}
-Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }}
-Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }}
- name: Publish Mac Artifacts
if: matrix.os == 'macOS-latest'
run: >
./gradlew release --no-daemon
-Ppublishing.enabled=true
-Ppublishing.platform=macosX64
-Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }}
-Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }}
-Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }}
-Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }}

View File

@ -2,12 +2,17 @@
## [Unreleased]
### Added
- Intrinsic value `two` for ExtendedField to work with hyperbolic functions
- ScaleOperations interface
### Changed
- Exponential operations merged with hyperbolic functions
### Deprecated
### Removed
- Nearest in Domain. To be implemented in geometry package.
- Number multiplication and division in main Algebra chain
### Fixed

View File

@ -20,7 +20,7 @@ allprojects {
}
group = "space.kscience"
version = "0.2.0"
version = "0.3.0"
}
subprojects {
@ -32,9 +32,8 @@ readme {
}
ksciencePublish {
spaceRepo = "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven"
bintrayRepo = "kscience"
githubProject = "kmath"
github("kmath")
space()
}
apiValidation {

View File

@ -6,7 +6,7 @@ import space.kscience.kmath.operations.RealField
fun main() {
val expr = RealField.mstInField {
val x = bindSymbol("x")
x * 2.0 + 2.0 / x - 16.0
x * 2.0 + 2.0 * one / x - 16.0
}
repeat(10000000) {

View File

@ -3,8 +3,8 @@ package space.kscience.kmath.structures
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.NumbersAddOperations
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.RingWithNumbers
import java.util.*
import java.util.stream.IntStream
@ -15,7 +15,7 @@ import java.util.stream.IntStream
class StreamRealNDField(
override val shape: IntArray,
) : NDField<Double, RealField>,
RingWithNumbers<NDStructure<Double>>,
NumbersAddOperations<NDStructure<Double>>,
ExtendedField<NDStructure<Double>> {
private val strides = DefaultStrides(shape)
@ -79,25 +79,29 @@ class StreamRealNDField(
return NDBuffer(strides, array.asBuffer())
}
override fun power(arg: NDStructure<Double>, pow: Number): NDBuffer<Double> = arg.map() { power(it, pow) }
override fun NDStructure<Double>.unaryMinus(): NDStructure<Double> = map { -it }
override fun exp(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { exp(it) }
override fun scale(a: NDStructure<Double>, value: Double): NDStructure<Double> = a.map { it * value }
override fun ln(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { ln(it) }
override fun power(arg: NDStructure<Double>, pow: Number): NDBuffer<Double> = arg.map { power(it, pow) }
override fun sin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { sin(it) }
override fun cos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { cos(it) }
override fun tan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { tan(it) }
override fun asin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { asin(it) }
override fun acos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { acos(it) }
override fun atan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { atan(it) }
override fun exp(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { exp(it) }
override fun sinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { sinh(it) }
override fun cosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { cosh(it) }
override fun tanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { tanh(it) }
override fun asinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { asinh(it) }
override fun acosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { acosh(it) }
override fun atanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map() { atanh(it) }
override fun ln(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { ln(it) }
override fun sin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { sin(it) }
override fun cos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { cos(it) }
override fun tan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { tan(it) }
override fun asin(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { asin(it) }
override fun acos(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { acos(it) }
override fun atan(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { atan(it) }
override fun sinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { sinh(it) }
override fun cosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { cosh(it) }
override fun tanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { tanh(it) }
override fun asinh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { asinh(it) }
override fun acosh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { acosh(it) }
override fun atanh(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { atanh(it) }
}
fun NDAlgebra.Companion.realWithStream(vararg shape: Int): StreamRealNDField = StreamRealNDField(shape)

View File

@ -1,9 +1,10 @@
kotlin.code.style=official
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.mpp.stability.nowarn=true
kotlin.native.enableDependencyPropagation=false
kotlin.parallel.tasks.in.project=true
org.gradle.configureondemand=true
org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m
org.gradle.parallel=true
systemProp.org.gradle.internal.publish.checksums.insecure=true
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -20,8 +20,8 @@ public object MstAlgebra : NumericAlgebra<MST> {
/**
* [Space] over [MST] nodes.
*/
public object MstSpace : Space<MST>, NumericAlgebra<MST> {
public override val zero: MST.Numeric by lazy { number(0.0) }
public object MstSpace : Space<MST>, NumericAlgebra<MST>, ScaleOperations<MST> {
public override val zero: MST.Numeric = number(0.0)
public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value)
public override fun bindSymbol(value: String): MST.Symbolic = MstAlgebra.bindSymbol(value)
@ -35,8 +35,8 @@ public object MstSpace : Space<MST>, NumericAlgebra<MST> {
public override operator fun MST.minus(b: MST): MST.Binary =
binaryOperationFunction(SpaceOperations.MINUS_OPERATION)(this, b)
public override fun multiply(a: MST, k: Number): MST.Binary =
binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(k))
public override fun scale(a: MST, value: Double): MST.Binary =
binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(value))
public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary =
MstAlgebra.binaryOperationFunction(operation)
@ -49,16 +49,17 @@ public object MstSpace : Space<MST>, NumericAlgebra<MST> {
* [Ring] over [MST] nodes.
*/
@OptIn(UnstableKMathAPI::class)
public object MstRing : Ring<MST>, RingWithNumbers<MST> {
public override val zero: MST.Numeric
get() = MstSpace.zero
public override val one: MST.Numeric by lazy { number(1.0) }
public object MstRing : Ring<MST>, NumbersAddOperations<MST>, ScaleOperations<MST> {
public override val zero: MST.Numeric = MstSpace.zero
public override val one: MST.Numeric = number(1.0)
public override fun number(value: Number): MST.Numeric = MstSpace.number(value)
public override fun bindSymbol(value: String): MST.Symbolic = MstSpace.bindSymbol(value)
public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b)
public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k)
public override fun scale(a: MST, value: Double): MST.Binary =
MstSpace.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstSpace.number(value))
public override fun multiply(a: MST, b: MST): MST.Binary =
binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b)
@ -77,17 +78,18 @@ public object MstRing : Ring<MST>, RingWithNumbers<MST> {
* [Field] over [MST] nodes.
*/
@OptIn(UnstableKMathAPI::class)
public object MstField : Field<MST>, RingWithNumbers<MST> {
public override val zero: MST.Numeric
get() = MstRing.zero
public object MstField : Field<MST>, NumbersAddOperations<MST>, ScaleOperations<MST> {
public override val zero: MST.Numeric get() = MstRing.zero
public override val one: MST.Numeric
get() = MstRing.one
public override val one: MST.Numeric get() = MstRing.one
public override fun bindSymbol(value: String): MST.Symbolic = MstRing.bindSymbol(value)
public override fun number(value: Number): MST.Numeric = MstRing.number(value)
public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b)
public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k)
public override fun scale(a: MST, value: Double): MST.Binary =
MstSpace.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstSpace.number(value))
public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b)
public override fun divide(a: MST, b: MST): MST.Binary =
binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b)
@ -107,11 +109,8 @@ public object MstField : Field<MST>, RingWithNumbers<MST> {
* [ExtendedField] over [MST] nodes.
*/
public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
public override val zero: MST.Numeric
get() = MstField.zero
public override val one: MST.Numeric
get() = MstField.one
public override val zero: MST.Numeric = MstField.zero
public override val one: MST.Numeric = MstField.one
public override fun bindSymbol(value: String): MST.Symbolic = MstField.bindSymbol(value)
public override fun number(value: Number): MST.Numeric = MstRing.number(value)
@ -121,14 +120,17 @@ public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
public override fun asin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg)
public override fun acos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg)
public override fun atan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg)
public override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.SINH_OPERATION)(arg)
public override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.COSH_OPERATION)(arg)
public override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.TANH_OPERATION)(arg)
public override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ASINH_OPERATION)(arg)
public override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ACOSH_OPERATION)(arg)
public override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ATANH_OPERATION)(arg)
public override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.SINH_OPERATION)(arg)
public override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.COSH_OPERATION)(arg)
public override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.TANH_OPERATION)(arg)
public override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ASINH_OPERATION)(arg)
public override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ACOSH_OPERATION)(arg)
public override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ATANH_OPERATION)(arg)
public override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b)
public override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k)
public override fun scale(a: MST, value: Double): MST =
binaryOperation(SpaceOperations.PLUS_OPERATION, a, number(value))
public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b)
public override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b)
public override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus }

View File

@ -15,9 +15,9 @@ internal class TestESTreeConsistencyWithInterpreter {
val res1 = MstSpace.mstInSpace {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
number(3.toByte()) - (number(2.toByte()) + (multiply(
number(3.toByte()) - (number(2.toByte()) + (scale(
add(number(1), number(1)),
2
2.0
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
),
@ -28,9 +28,9 @@ internal class TestESTreeConsistencyWithInterpreter {
val res2 = MstSpace.mstInSpace {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
number(3.toByte()) - (number(2.toByte()) + (multiply(
number(3.toByte()) - (number(2.toByte()) + (scale(
add(number(1), number(1)),
2
2.0
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
),
@ -46,9 +46,9 @@ internal class TestESTreeConsistencyWithInterpreter {
val res1 = ByteRing.mstInRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (multiply(
(bindSymbol("x") - (2.toByte() + (scale(
add(number(1), number(1)),
2
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
),
@ -59,9 +59,9 @@ internal class TestESTreeConsistencyWithInterpreter {
val res2 = ByteRing.mstInRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (multiply(
(bindSymbol("x") - (2.toByte() + (scale(
add(number(1), number(1)),
2
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
),
number(1)
@ -75,7 +75,7 @@ internal class TestESTreeConsistencyWithInterpreter {
fun realField() {
val res1 = RealField.mstInField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -83,7 +83,7 @@ internal class TestESTreeConsistencyWithInterpreter {
val res2 = RealField.mstInField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -96,7 +96,7 @@ internal class TestESTreeConsistencyWithInterpreter {
fun complexField() {
val res1 = ComplexField.mstInField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -104,7 +104,7 @@ internal class TestESTreeConsistencyWithInterpreter {
val res2 = ComplexField.mstInField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero

View File

@ -15,9 +15,9 @@ internal class TestAsmConsistencyWithInterpreter {
val res1 = MstSpace.mstInSpace {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
number(3.toByte()) - (number(2.toByte()) + (multiply(
number(3.toByte()) - (number(2.toByte()) + (scale(
add(number(1), number(1)),
2
2.0
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
),
@ -28,9 +28,9 @@ internal class TestAsmConsistencyWithInterpreter {
val res2 = MstSpace.mstInSpace {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
number(3.toByte()) - (number(2.toByte()) + (multiply(
number(3.toByte()) - (number(2.toByte()) + (scale(
add(number(1), number(1)),
2
2.0
) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
),
@ -46,9 +46,9 @@ internal class TestAsmConsistencyWithInterpreter {
val res1 = ByteRing.mstInRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (multiply(
(bindSymbol("x") - (2.toByte() + (scale(
add(number(1), number(1)),
2
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
),
@ -59,9 +59,9 @@ internal class TestAsmConsistencyWithInterpreter {
val res2 = ByteRing.mstInRing {
binaryOperationFunction("+")(
unaryOperationFunction("+")(
(bindSymbol("x") - (2.toByte() + (multiply(
(bindSymbol("x") - (2.toByte() + (scale(
add(number(1), number(1)),
2
2.0
) + 1.toByte()))) * 3.0 - 1.toByte()
),
number(1)
@ -75,7 +75,7 @@ internal class TestAsmConsistencyWithInterpreter {
fun realField() {
val res1 = RealField.mstInField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -83,7 +83,7 @@ internal class TestAsmConsistencyWithInterpreter {
val res2 = RealField.mstInField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -96,7 +96,7 @@ internal class TestAsmConsistencyWithInterpreter {
fun complexField() {
val res1 = ComplexField.mstInField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero
@ -104,7 +104,7 @@ internal class TestAsmConsistencyWithInterpreter {
val res2 = ComplexField.mstInField {
+(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (bindSymbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
(3.0 - (bindSymbol("x") + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
) + zero

View File

@ -4,7 +4,7 @@ import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
import space.kscience.kmath.expressions.*
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.RingWithNumbers
import space.kscience.kmath.operations.NumbersAddOperations
/**
* A field over commons-math [DerivativeStructure].
@ -16,7 +16,8 @@ import space.kscience.kmath.operations.RingWithNumbers
public class DerivativeStructureField(
public val order: Int,
bindings: Map<Symbol, Double>,
) : ExtendedField<DerivativeStructure>, ExpressionAlgebra<Double, DerivativeStructure>, RingWithNumbers<DerivativeStructure> {
) : ExtendedField<DerivativeStructure>, ExpressionAlgebra<Double, DerivativeStructure>,
NumbersAddOperations<DerivativeStructure> {
public val numberOfVariables: Int = bindings.size
public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) }
@ -62,13 +63,11 @@ public class DerivativeStructureField(
public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList())
override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate()
public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b)
public override fun multiply(a: DerivativeStructure, k: Number): DerivativeStructure = when (k) {
is Double -> a.multiply(k)
is Int -> a.multiply(k)
else -> a.multiply(k.toDouble())
}
public override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value)
public override fun multiply(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.multiply(b)
public override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b)

View File

@ -101,8 +101,8 @@ public object CMMatrixContext : MatrixContext<Double, CMMatrix> {
public override operator fun Matrix<Double>.minus(b: Matrix<Double>): CMMatrix =
CMMatrix(toCM().origin.subtract(b.toCM().origin))
public override fun multiply(a: Matrix<Double>, k: Number): CMMatrix =
CMMatrix(a.toCM().origin.scalarMultiply(k.toDouble()))
// public override fun multiply(a: Matrix<Double>, k: Number): CMMatrix =
// CMMatrix(a.toCM().origin.scalarMultiply(k.toDouble()))
public override operator fun Matrix<Double>.times(value: Double): CMMatrix =
produce(rowNum, colNum) { i, j -> get(i, j) * value }

View File

@ -4,10 +4,7 @@ import space.kscience.kmath.memory.MemoryReader
import space.kscience.kmath.memory.MemorySpec
import space.kscience.kmath.memory.MemoryWriter
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.FieldElement
import space.kscience.kmath.operations.Norm
import space.kscience.kmath.operations.RingWithNumbers
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MemoryBuffer
import space.kscience.kmath.structures.MutableBuffer
@ -47,7 +44,8 @@ private val PI_DIV_2 = Complex(PI / 2, 0)
* A field of [Complex].
*/
@OptIn(UnstableKMathAPI::class)
public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, RingWithNumbers<Complex> {
public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, NumbersAddOperations<Complex>,
ScaleOperations<Complex> {
public override val zero: Complex = 0.0.toComplex()
public override val one: Complex = 1.0.toComplex()
@ -56,8 +54,14 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Rin
*/
public val i: Complex by lazy { Complex(0.0, 1.0) }
override fun Complex.unaryMinus(): Complex = Complex(-re, -im)
override fun number(value: Number): Complex = Complex(value.toDouble(), 0.0)
override fun scale(a: Complex, value: Double): Complex = Complex(a.re * value, a.im * value)
public override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im)
public override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble())
// public override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble())
public override fun multiply(a: Complex, b: Complex): Complex =
Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re)
@ -86,8 +90,10 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Rin
}
}
public override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2
public override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2
override operator fun Complex.div(k: Number): Complex = Complex(re / k.toDouble(), im / k.toDouble())
public override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2.0
public override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2.0
public override fun tan(arg: Complex): Complex {
val e1 = exp(-i * arg)
@ -159,7 +165,8 @@ public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, Rin
public override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg)
public override fun bindSymbol(value: String): Complex = if (value == "i") i else super<ExtendedField>.bindSymbol(value)
public override fun bindSymbol(value: String): Complex =
if (value == "i") i else super<ExtendedField>.bindSymbol(value)
}
/**
@ -181,7 +188,8 @@ public data class Complex(val re: Double, val im: Double) : FieldElement<Complex
public override val objectSize: Int
get() = 16
public override fun MemoryReader.read(offset: Int): Complex = Complex(readDouble(offset), readDouble(offset + 8))
public override fun MemoryReader.read(offset: Int): Complex =
Complex(readDouble(offset), readDouble(offset + 8))
public override fun MemoryWriter.write(offset: Int, value: Complex) {
writeDouble(offset, value.re)

View File

@ -6,7 +6,7 @@ import space.kscience.kmath.nd.NDAlgebra
import space.kscience.kmath.nd.NDBuffer
import space.kscience.kmath.nd.NDStructure
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.RingWithNumbers
import space.kscience.kmath.operations.NumbersAddOperations
import space.kscience.kmath.structures.Buffer
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
@ -19,7 +19,7 @@ import kotlin.contracts.contract
public class ComplexNDField(
shape: IntArray,
) : BufferedNDField<Complex, ComplexField>(shape, ComplexField, Buffer.Companion::complex),
RingWithNumbers<NDStructure<Complex>>,
NumbersAddOperations<NDStructure<Complex>>,
ExtendedField<NDStructure<Complex>> {
override val zero: NDBuffer<Complex> by lazy { produce { zero } }
@ -29,6 +29,7 @@ public class ComplexNDField(
val d = value.toComplex() // minimize conversions
return produce { d }
}
//
// @Suppress("OVERRIDE_BY_INLINE")
// override inline fun map(
@ -75,25 +76,25 @@ public class ComplexNDField(
// return BufferedNDFieldElement(this, buffer)
// }
override fun power(arg: NDStructure<Complex>, pow: Number): NDBuffer<Complex> = arg.map() { power(it, pow) }
override fun power(arg: NDStructure<Complex>, pow: Number): NDBuffer<Complex> = arg.map { power(it, pow) }
override fun exp(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { exp(it) }
override fun exp(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { exp(it) }
override fun ln(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { ln(it) }
override fun ln(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { ln(it) }
override fun sin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { sin(it) }
override fun cos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { cos(it) }
override fun tan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { tan(it) }
override fun asin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { asin(it) }
override fun acos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { acos(it) }
override fun atan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { atan(it) }
override fun sin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { sin(it) }
override fun cos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { cos(it) }
override fun tan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { tan(it) }
override fun asin(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { asin(it) }
override fun acos(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { acos(it) }
override fun atan(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { atan(it) }
override fun sinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { sinh(it) }
override fun cosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { cosh(it) }
override fun tanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { tanh(it) }
override fun asinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { asinh(it) }
override fun acosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { acosh(it) }
override fun atanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map() { atanh(it) }
override fun sinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { sinh(it) }
override fun cosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { cosh(it) }
override fun tanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { tanh(it) }
override fun asinh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { asinh(it) }
override fun acosh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { acosh(it) }
override fun atanh(arg: NDStructure<Complex>): NDBuffer<Complex> = arg.map { atanh(it) }
}

View File

@ -37,7 +37,7 @@ public val Quaternion.r: Double
*/
@OptIn(UnstableKMathAPI::class)
public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Quaternion>, PowerOperations<Quaternion>,
ExponentialOperations<Quaternion>, RingWithNumbers<Quaternion> {
ExponentialOperations<Quaternion>, NumbersAddOperations<Quaternion>, ScaleOperations<Quaternion> {
override val zero: Quaternion = 0.toQuaternion()
override val one: Quaternion = 1.toQuaternion()
@ -59,10 +59,8 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Quaternion>,
public override fun add(a: Quaternion, b: Quaternion): Quaternion =
Quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z)
public override fun multiply(a: Quaternion, k: Number): Quaternion {
val d = k.toDouble()
return Quaternion(a.w * d, a.x * d, a.y * d, a.z * d)
}
public override fun scale(a: Quaternion, value: Double): Quaternion =
Quaternion(a.w * value, a.x * value, a.y * value, a.z * value)
public override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion(
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
@ -173,6 +171,15 @@ public object QuaternionField : Field<Quaternion>, Norm<Quaternion, Quaternion>,
"k" -> k
else -> super<Field>.bindSymbol(value)
}
override fun number(value: Number): Quaternion =value.toQuaternion()
public override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0
public override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0
public override fun tanh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg))
public override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(arg * arg + one) + arg)
public override fun acosh(arg: Quaternion): Quaternion = ln(arg + sqrt((arg - one) * (arg + one)))
public override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0
}
/**
@ -207,8 +214,7 @@ public data class Quaternion(
require(!z.isNaN()) { "x-component of quaternion is not-a-number" }
}
public override val context: QuaternionField
get() = QuaternionField
public override val context: QuaternionField get() = QuaternionField
/**
* Returns a string representation of this quaternion.

View File

@ -4,7 +4,6 @@ import space.kscience.kmath.expressions.FunctionalExpressionField
import space.kscience.kmath.expressions.bindSymbol
import space.kscience.kmath.expressions.invoke
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.operations.invoke
import kotlin.test.Test
import kotlin.test.assertEquals
@ -13,14 +12,11 @@ internal class ExpressionFieldForComplexTest {
@Test
fun testComplex() {
val context = FunctionalExpressionField(ComplexField)
val expression = context {
val expression = FunctionalExpressionField(ComplexField).run {
val x = bindSymbol(x)
x * x + 2 * x + one
}
assertEquals(expression(x to Complex(1.0, 0.0)), Complex(4.0, 0.0))
//assertEquals(expression(), Complex(9.0, 0.0))
}
}

View File

@ -1,55 +0,0 @@
# The Core Module (`kmath-core`)
The core features of KMath:
- [algebras](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
- [nd](src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
- [linear](src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition.
- [buffers](src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
- [expressions](src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high
performance calculations to code generation.
- [domains](src/commonMain/kotlin/kscience/kmath/domains) : Domains
- [autodif](src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
> #### Artifact:
>
> This module artifact: `space.kscience:kmath-core:0.2.0`.
>
> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
>
> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
>
> **Gradle:**
>
> ```gradle
> repositories {
> maven { url 'https://repo.kotlin.link' }
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
>// Uncomment if repo.kotlin.link is unavailable
>// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
>// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
> }
>
> dependencies {
> implementation 'space.kscience:kmath-core:0.2.0'
> }
> ```
> **Gradle Kotlin DSL:**
>
> ```kotlin
> repositories {
> maven("https://repo.kotlin.link")
> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
>// Uncomment if repo.kotlin.link is unavailable
>// maven("https://dl.bintray.com/mipt-npm/kscience")
>// maven("https://dl.bintray.com/mipt-npm/dev")
> }
>
> dependencies {
> implementation("space.kscience:kmath-core:0.2.0")
> }
> ```

File diff suppressed because it is too large Load Diff

View File

@ -16,8 +16,8 @@
package space.kscience.kmath.domains
import space.kscience.kmath.linear.Point
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.RealBuffer
import space.kscience.kmath.structures.indices
/**
@ -26,6 +26,7 @@ import space.kscience.kmath.structures.indices
*
* @author Alexander Nozik
*/
@UnstableKMathAPI
public class HyperSquareDomain(private val lower: Buffer<Double>, private val upper: Buffer<Double>) : RealDomain {
public override val dimension: Int get() = lower.size
@ -33,26 +34,10 @@ public class HyperSquareDomain(private val lower: Buffer<Double>, private val up
point[i] in lower[i]..upper[i]
}
public override fun getLowerBound(num: Int, point: Point<Double>): Double = lower[num]
public override fun getLowerBound(num: Int): Double = lower[num]
public override fun getUpperBound(num: Int, point: Point<Double>): Double = upper[num]
public override fun getUpperBound(num: Int): Double = upper[num]
public override fun nearestInDomain(point: Point<Double>): Point<Double> {
val res = DoubleArray(point.size) { i ->
when {
point[i] < lower[i] -> lower[i]
point[i] > upper[i] -> upper[i]
else -> point[i]
}
}
return RealBuffer(*res)
}
public override fun volume(): Double {
var res = 1.0

View File

@ -15,45 +15,27 @@
*/
package space.kscience.kmath.domains
import space.kscience.kmath.linear.Point
import space.kscience.kmath.misc.UnstableKMathAPI
/**
* n-dimensional volume
*
* @author Alexander Nozik
*/
@UnstableKMathAPI
public interface RealDomain : Domain<Double> {
public fun nearestInDomain(point: Point<Double>): Point<Double>
/**
* The lower edge for the domain going down from point
* @param num
* @param point
* @return
*/
public fun getLowerBound(num: Int, point: Point<Double>): Double?
/**
* The upper edge of the domain going up from point
* @param num
* @param point
* @return
*/
public fun getUpperBound(num: Int, point: Point<Double>): Double?
/**
* Global lower edge
* @param num
* @return
* @param num axis number
*/
public fun getLowerBound(num: Int): Double?
public fun getLowerBound(num: Int): Double
/**
* Global upper edge
* @param num
* @return
* @param num axis number
*/
public fun getUpperBound(num: Int): Double?
public fun getUpperBound(num: Int): Double
/**
* Hyper volume

View File

@ -16,19 +16,15 @@
package space.kscience.kmath.domains
import space.kscience.kmath.linear.Point
import space.kscience.kmath.misc.UnstableKMathAPI
@UnstableKMathAPI
public class UnconstrainedDomain(public override val dimension: Int) : RealDomain {
public override operator fun contains(point: Point<Double>): Boolean = true
public override fun getLowerBound(num: Int, point: Point<Double>): Double? = Double.NEGATIVE_INFINITY
public override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY
public override fun getLowerBound(num: Int): Double? = Double.NEGATIVE_INFINITY
public override fun getUpperBound(num: Int, point: Point<Double>): Double? = Double.POSITIVE_INFINITY
public override fun getUpperBound(num: Int): Double? = Double.POSITIVE_INFINITY
public override fun nearestInDomain(point: Point<Double>): Point<Double> = point
public override fun getUpperBound(num: Int): Double = Double.POSITIVE_INFINITY
public override fun volume(): Double = Double.POSITIVE_INFINITY
}

View File

@ -1,11 +1,11 @@
package space.kscience.kmath.domains
import space.kscience.kmath.linear.Point
import space.kscience.kmath.structures.asBuffer
import space.kscience.kmath.misc.UnstableKMathAPI
@UnstableKMathAPI
public inline class UnivariateDomain(public val range: ClosedFloatingPointRange<Double>) : RealDomain {
public override val dimension: Int
get() = 1
public override val dimension: Int get() = 1
public operator fun contains(d: Double): Boolean = range.contains(d)
@ -14,33 +14,12 @@ public inline class UnivariateDomain(public val range: ClosedFloatingPointRange<
return contains(point[0])
}
public 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()
}
}
public override fun getLowerBound(num: Int, point: Point<Double>): Double? {
public override fun getLowerBound(num: Int): Double {
require(num == 0)
return range.start
}
public override fun getUpperBound(num: Int, point: Point<Double>): Double? {
require(num == 0)
return range.endInclusive
}
public override fun getLowerBound(num: Int): Double? {
require(num == 0)
return range.start
}
public override fun getUpperBound(num: Int): Double? {
public override fun getUpperBound(num: Int): Double {
require(num == 0)
return range.endInclusive
}

View File

@ -48,18 +48,21 @@ public open class FunctionalExpressionSpace<T, A : Space<T>>(
) : FunctionalExpressionAlgebra<T, A>(algebra), Space<Expression<T>> {
public override val zero: Expression<T> get() = const(algebra.zero)
override fun Expression<T>.unaryMinus(): Expression<T> =
unaryOperation(SpaceOperations.MINUS_OPERATION, this)
/**
* Builds an Expression of addition of two another expressions.
*/
public override fun add(a: Expression<T>, b: Expression<T>): Expression<T> =
binaryOperationFunction(SpaceOperations.PLUS_OPERATION)(a, b)
binaryOperation(SpaceOperations.PLUS_OPERATION, a, b)
/**
* Builds an Expression of multiplication of expression by number.
*/
public override fun multiply(a: Expression<T>, k: Number): Expression<T> = Expression { arguments ->
algebra.multiply(a.invoke(arguments), k)
}
// /**
// * Builds an Expression of multiplication of expression by number.
// */
// public override fun multiply(a: Expression<T>, k: Number): Expression<T> = Expression { arguments ->
// algebra.multiply(a.invoke(arguments), k)
// }
public operator fun Expression<T>.plus(arg: T): Expression<T> = this + const(arg)
public operator fun Expression<T>.minus(arg: T): Expression<T> = this - const(arg)
@ -71,13 +74,13 @@ public open class FunctionalExpressionSpace<T, A : Space<T>>(
public override fun binaryOperationFunction(operation: String): (left: Expression<T>, right: Expression<T>) -> Expression<T> =
super<FunctionalExpressionAlgebra>.binaryOperationFunction(operation)
}
public open class FunctionalExpressionRing<T, A : Ring<T>>(
algebra: A,
) : FunctionalExpressionSpace<T, A>(algebra), Ring<Expression<T>> {
public override val one: Expression<T>
get() = const(algebra.one)
public override val one: Expression<T> get() = const(algebra.one)
/**
* Builds an Expression of multiplication of two expressions.
@ -97,7 +100,8 @@ public open class FunctionalExpressionRing<T, A : Ring<T>>(
public open class FunctionalExpressionField<T, A: Field<T>>(
algebra: A,
) : FunctionalExpressionRing<T, A>(algebra), Field<Expression<T>> {
) : FunctionalExpressionRing<T, A>(algebra), Field<Expression<T>>,
ScaleOperations<Expression<T>> {
/**
* Builds an Expression of division an expression by another one.
*/
@ -112,6 +116,10 @@ public open class FunctionalExpressionField<T, A : Field<T>>(
public override fun binaryOperationFunction(operation: String): (left: Expression<T>, right: Expression<T>) -> Expression<T> =
super<FunctionalExpressionRing>.binaryOperationFunction(operation)
override fun scale(a: Expression<T>, value: Double): Expression<T> = algebra {
Expression { args -> a(args) * value }
}
}
public open class FunctionalExpressionExtendedField<T, A : ExtendedField<T>>(
@ -160,5 +168,6 @@ public inline fun <T, A : Ring<T>> A.expressionInRing(block: FunctionalExpressio
public inline fun <T, A : Field<T>> A.expressionInField(block: FunctionalExpressionField<T, A>.() -> Expression<T>): Expression<T> =
FunctionalExpressionField(this).block()
public inline fun <T, A : ExtendedField<T>> A.expressionInExtendedField(block: FunctionalExpressionExtendedField<T, A>.() -> Expression<T>): Expression<T> =
FunctionalExpressionExtendedField(this).block()
public inline fun <T, A : ExtendedField<T>> A.expressionInExtendedField(
block: FunctionalExpressionExtendedField<T, A>.() -> Expression<T>,
): Expression<T> = FunctionalExpressionExtendedField(this).block()

View File

@ -47,36 +47,6 @@ public fun <T : Any> DerivationResult<T>.grad(vararg variables: Symbol): Point<T
return variables.map(::derivative).asBuffer()
}
/**
* Runs differentiation and establishes [SimpleAutoDiffField] context inside the block of code.
*
* The partial derivatives are placed in argument `d` variable
*
* Example:
* ```
* val x by symbol // define variable(s) and their values
* val y = RealField.withAutoDiff() { sqr(x) + 5 * x + 3 } // write formulate in deriv context
* assertEquals(17.0, y.x) // the value of result (y)
* assertEquals(9.0, x.d) // dy/dx
* ```
*
* @param body the action in [SimpleAutoDiffField] context returning [AutoDiffVariable] to differentiate with respect to.
* @return the result of differentiation.
*/
public fun <T : Any, F : Field<T>> F.simpleAutoDiff(
bindings: Map<Symbol, T>,
body: SimpleAutoDiffField<T, F>.() -> AutoDiffValue<T>,
): DerivationResult<T> {
contract { callsInPlace(body, InvocationKind.EXACTLY_ONCE) }
return SimpleAutoDiffField(this, bindings).differentiate(body)
}
public fun <T : Any, F : Field<T>> F.simpleAutoDiff(
vararg bindings: Pair<Symbol, T>,
body: SimpleAutoDiffField<T, F>.() -> AutoDiffValue<T>,
): DerivationResult<T> = simpleAutoDiff(bindings.toMap(), body)
/**
* Represents field in context of which functions can be derived.
*/
@ -84,12 +54,9 @@ public fun <T : Any, F : Field<T>> F.simpleAutoDiff(
public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
public val context: F,
bindings: Map<Symbol, T>,
) : Field<AutoDiffValue<T>>, ExpressionAlgebra<T, AutoDiffValue<T>>, RingWithNumbers<AutoDiffValue<T>> {
public override val zero: AutoDiffValue<T>
get() = const(context.zero)
public override val one: AutoDiffValue<T>
get() = const(context.one)
) : Field<AutoDiffValue<T>>, ExpressionAlgebra<T, AutoDiffValue<T>>, NumbersAddOperations<AutoDiffValue<T>> {
public override val zero: AutoDiffValue<T> get() = const(context.zero)
public override val one: AutoDiffValue<T> get() = const(context.one)
// this stack contains pairs of blocks and values to apply them to
private var stack: Array<Any?> = arrayOfNulls<Any?>(8)
@ -137,6 +104,8 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
override fun const(value: T): AutoDiffValue<T> = AutoDiffValue(value)
override fun number(value: Number): AutoDiffValue<T> = const { one * value }
/**
* A variable accessing inner state of derivatives.
* Use this value in inner builders to avoid creating additional derivative bindings.
@ -175,21 +144,24 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
return DerivationResult(result.value, bindings.mapValues { it.value.d }, context)
}
// Overloads for Double constants
// // Overloads for Double constants
//
// public override operator fun Number.plus(b: AutoDiffValue<T>): AutoDiffValue<T> =
// derive(const { this@plus.toDouble() * one + b.value }) { z ->
// b.d += z.d
// }
//
// public override operator fun AutoDiffValue<T>.plus(b: Number): AutoDiffValue<T> = b.plus(this)
//
// public override operator fun Number.minus(b: AutoDiffValue<T>): AutoDiffValue<T> =
// derive(const { this@minus.toDouble() * one - b.value }) { z -> b.d -= z.d }
//
// public override operator fun AutoDiffValue<T>.minus(b: Number): AutoDiffValue<T> =
// derive(const { this@minus.value - one * b.toDouble() }) { z -> d += z.d }
public override operator fun Number.plus(b: AutoDiffValue<T>): AutoDiffValue<T> =
derive(const { this@plus.toDouble() * one + b.value }) { z ->
b.d += z.d
}
public override operator fun AutoDiffValue<T>.plus(b: Number): AutoDiffValue<T> = b.plus(this)
public override operator fun Number.minus(b: AutoDiffValue<T>): AutoDiffValue<T> =
derive(const { this@minus.toDouble() * one - b.value }) { z -> b.d -= z.d }
public override operator fun AutoDiffValue<T>.minus(b: Number): AutoDiffValue<T> =
derive(const { this@minus.value - one * b.toDouble() }) { z -> this@minus.d += z.d }
override fun AutoDiffValue<T>.unaryMinus(): AutoDiffValue<T> =
derive(const { -value }) { z -> d -= z.d }
// Basic math (+, -, *, /)
@ -211,12 +183,44 @@ public open class SimpleAutoDiffField<T : Any, F : Field<T>>(
b.d -= z.d * a.value / (b.value * b.value)
}
public override fun multiply(a: AutoDiffValue<T>, k: Number): AutoDiffValue<T> =
derive(const { k.toDouble() * a.value }) { z ->
a.d += z.d * k.toDouble()
public override fun scale(a: AutoDiffValue<T>, value: Double): AutoDiffValue<T> =
derive(const { value * a.value }) { z ->
a.d += z.d * value
}
}
/**
* Runs differentiation and establishes [SimpleAutoDiffField] context inside the block of code.
*
* The partial derivatives are placed in argument `d` variable
*
* Example:
* ```
* val x by symbol // define variable(s) and their values
* val y = RealField.withAutoDiff() { sqr(x) + 5 * x + 3 } // write formulate in deriv context
* assertEquals(17.0, y.x) // the value of result (y)
* assertEquals(9.0, x.d) // dy/dx
* ```
*
* @param body the action in [SimpleAutoDiffField] context returning [AutoDiffVariable] to differentiate with respect to.
* @return the result of differentiation.
*/
public fun <T : Any, F : Field<T>> F.simpleAutoDiff(
bindings: Map<Symbol, T>,
body: SimpleAutoDiffField<T, F>.() -> AutoDiffValue<T>,
): DerivationResult<T> {
contract { callsInPlace(body, InvocationKind.EXACTLY_ONCE) }
return SimpleAutoDiffField(this, bindings).differentiate(body)
}
public fun <T : Any, F : Field<T>> F.simpleAutoDiff(
vararg bindings: Pair<Symbol, T>,
body: SimpleAutoDiffField<T, F>.() -> AutoDiffValue<T>,
): DerivationResult<T> = simpleAutoDiff(bindings.toMap(), body)
/**
* A constructs that creates a derivative structure with required order on-demand
*/
@ -247,19 +251,20 @@ public fun <T : Any, F : Field<T>> simpleAutoDiff(field: F): AutoDiffProcessor<T
// Extensions for differentiation of various basic mathematical functions
// x ^ 2
public fun <T : Any, F : Field<T>> SimpleAutoDiffField<T, F>.sqr(x: AutoDiffValue<T>): AutoDiffValue<T> =
derive(const { x.value * x.value }) { z -> x.d += z.d * 2 * x.value }
public fun <T : Any, F : ExtendedField<T>> SimpleAutoDiffField<T, F>.sqr(x: AutoDiffValue<T>): AutoDiffValue<T> =
derive(const { x.value * x.value }) { z -> x.d += z.d * 2.0 * x.value }
// x ^ 1/2
public fun <T : Any, F : ExtendedField<T>> SimpleAutoDiffField<T, F>.sqrt(x: AutoDiffValue<T>): AutoDiffValue<T> =
derive(const { sqrt(x.value) }) { z -> x.d += z.d * 0.5 / z.value }
derive(const { sqrt(x.value) }) { z -> x.d += z.d / 2.0 / z.value }
// x ^ y (const)
public fun <T : Any, F : ExtendedField<T>> SimpleAutoDiffField<T, F>.pow(
x: AutoDiffValue<T>,
y: Double,
): AutoDiffValue<T> =
derive(const { power(x.value, y) }) { z -> x.d += z.d * y * power(x.value, y - 1) }
): AutoDiffValue<T> = derive(const { power(x.value, y) }) { z ->
x.d += z.d * y * power(x.value, y - 1)
}
public fun <T : Any, F : ExtendedField<T>> SimpleAutoDiffField<T, F>.pow(
x: AutoDiffValue<T>,
@ -328,7 +333,13 @@ public fun <T : Any, F : ExtendedField<T>> SimpleAutoDiffField<T, F>.atanh(x: Au
public class SimpleAutoDiffExtendedField<T : Any, F : ExtendedField<T>>(
context: F,
bindings: Map<Symbol, T>,
) : ExtendedField<AutoDiffValue<T>>, SimpleAutoDiffField<T, F>(context, bindings) {
) : ExtendedField<AutoDiffValue<T>>, ScaleOperations<AutoDiffValue<T>>,
SimpleAutoDiffField<T, F>(context, bindings) {
override fun number(value: Number): AutoDiffValue<T> = const { number(value) }
override fun scale(a: AutoDiffValue<T>, value: Double): AutoDiffValue<T> = a * number(value)
// x ^ 2
public fun sqr(x: AutoDiffValue<T>): AutoDiffValue<T> =
(this as SimpleAutoDiffField<T, F>).sqr(x)

View File

@ -78,12 +78,12 @@ public class BufferMatrixContext<T : Any, R : Ring<T>>(
}
}
override fun multiply(a: Matrix<T>, k: Number): BufferMatrix<T> {
val aBufferMatrix = a.toBufferMatrix()
return elementContext {
produce(a.rowNum, a.colNum) { i, j -> aBufferMatrix[i, j] * k.toDouble() }
}
}
// override fun multiply(a: Matrix<T>, k: Number): BufferMatrix<T> {
// val aBufferMatrix = a.toBufferMatrix()
// return elementContext {
// produce(a.rowNum, a.colNum) { i, j -> aBufferMatrix[i, j] * k.toDouble() }
// }
// }
public companion object
}

View File

@ -1,10 +1,7 @@
package space.kscience.kmath.linear
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.SpaceOperations
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.operations.sum
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.BufferFactory
import space.kscience.kmath.structures.asSequence
@ -167,9 +164,9 @@ public interface GenericMatrixContext<T : Any, R : Ring<T>, out M : Matrix<T>> :
return produce(rowNum, colNum) { i, j -> elementContext { get(i, j) + b[i, j] } }
}
public override fun multiply(a: Matrix<T>, k: Number): M =
produce(a.rowNum, a.colNum) { i, j -> elementContext { a[i, j] * k } }
//
// public override fun multiply(a: Matrix<T>, k: Number): M =
// produce(a.rowNum, a.colNum) { i, j -> elementContext { a[i, j] * k } }
public override operator fun Matrix<T>.times(value: T): M =
produce(rowNum, colNum) { i, j -> elementContext { get(i, j) * value } }

View File

@ -21,6 +21,8 @@ public object RealMatrixContext : MatrixContext<Double, BufferMatrix<Double>> {
if (i == j) 1.0 else 0.0
} + DiagonalFeature
override fun Matrix<Double>.unaryMinus(): Matrix<Double> = produce(rowNum, colNum) { i, j -> -get(i, j) }
public override infix fun Matrix<Double>.dot(other: Matrix<Double>): BufferMatrix<Double> {
require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" }
val bufferMatrix = toBufferMatrix()
@ -60,12 +62,16 @@ public object RealMatrixContext : MatrixContext<Double, BufferMatrix<Double>> {
val bufferMatrix = toBufferMatrix()
return produce(rowNum, colNum) { i, j -> bufferMatrix[i, j] * value }
}
override fun multiply(a: Matrix<Double>, k: Number): BufferMatrix<Double> {
val aBufferMatrix = a.toBufferMatrix()
return produce(a.rowNum, a.colNum) { i, j -> aBufferMatrix[i, j] * k.toDouble() }
}
//
// override fun multiply(a: Matrix<Double>, k: Number): BufferMatrix<Double> {
// val aBufferMatrix = a.toBufferMatrix()
// return produce(a.rowNum, a.colNum) { i, j -> aBufferMatrix[i, j] * k.toDouble() }
// }
//
// override fun divide(a: Matrix<Double>, k: Number): BufferMatrix<Double> {
// val aBufferMatrix = a.toBufferMatrix()
// return produce(a.rowNum, a.colNum) { i, j -> aBufferMatrix[i, j] / k.toDouble() }
// }
}

View File

@ -1,6 +1,7 @@
package space.kscience.kmath.linear
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.Space
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer
@ -10,21 +11,18 @@ import space.kscience.kmath.structures.BufferFactory
* A linear space for vectors.
* Could be used on any point-like structure
*/
public interface VectorSpace<T : Any, S : Space<T>> : Space<Point<T>> {
public interface VectorSpace<T : Any, A : Ring<T>> : Space<Point<T>> {
public val size: Int
public val space: S
override val zero: Point<T> get() = produce { space.zero }
public val algebra: A
override val zero: Point<T> get() = produce { algebra.zero }
public fun produce(initializer: S.(Int) -> T): Point<T>
public fun produce(initializer: A.(Int) -> T): Point<T>
/**
* Produce a space-element of this vector space for expressions
*/
//fun produceElement(initializer: (Int) -> T): Vector<T, S>
override fun add(a: Point<T>, b: Point<T>): Point<T> = produce { algebra { a[it] + b[it] } }
override fun add(a: Point<T>, b: Point<T>): Point<T> = produce { space { a[it] + b[it] } }
public fun scale(a: Point<T>, scale: T): Point<T> = produce { algebra { a[it] * scale } }
override fun multiply(a: Point<T>, k: Number): Point<T> = produce { space { a[it] * k } }
override fun Point<T>.unaryMinus(): Point<T> = produce { -get(it) }
//TODO add basis
@ -45,26 +43,25 @@ public interface VectorSpace<T : Any, S : Space<T>> : Space<Point<T>> {
/**
* A structured vector space with custom buffer
*/
public fun <T : Any, S : Space<T>> buffered(
public fun <T : Any, A : Ring<T>> buffered(
size: Int,
space: S,
space: A,
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
): BufferVectorSpace<T, S> = BufferVectorSpace(size, space, bufferFactory)
): BufferVectorSpace<T, A> = BufferVectorSpace(size, space, bufferFactory)
/**
* Automatic buffered vector, unboxed if it is possible
*/
public inline fun <reified T : Any, S : Space<T>> auto(size: Int, space: S): VectorSpace<T, S> =
public inline fun <reified T : Any, A : Ring<T>> auto(size: Int, space: A): VectorSpace<T, A> =
buffered(size, space, Buffer.Companion::auto)
}
}
public class BufferVectorSpace<T : Any, S : Space<T>>(
public class BufferVectorSpace<T : Any, A : Ring<T>>(
override val size: Int,
override val space: S,
override val algebra: A,
public val bufferFactory: BufferFactory<T>,
) : VectorSpace<T, S> {
override fun produce(initializer: S.(Int) -> T): Buffer<T> = bufferFactory(size) { space.initializer(it) }
//override fun produceElement(initializer: (Int) -> T): Vector<T, S> = BufferVector(this, produce(initializer))
) : VectorSpace<T, A> {
override fun produce(initializer: A.(Int) -> T): Buffer<T> = bufferFactory(size) { algebra.initializer(it) }
}

View File

@ -1,19 +1,16 @@
package space.kscience.kmath.nd
import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.Space
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.BufferFactory
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
public interface BufferNDAlgebra<T, C> : NDAlgebra<T, C> {
public interface BufferNDAlgebra<T, A : Algebra<T>> : NDAlgebra<T, A> {
public val strides: Strides
public val bufferFactory: BufferFactory<T>
override fun produce(initializer: C.(IntArray) -> T): NDBuffer<T> = NDBuffer(
override fun produce(initializer: A.(IntArray) -> T): NDBuffer<T> = NDBuffer(
strides,
bufferFactory(strides.linearSize) { offset ->
elementContext.initializer(strides.index(offset))
@ -30,14 +27,14 @@ public interface BufferNDAlgebra<T, C> : NDAlgebra<T, C> {
else -> bufferFactory(strides.linearSize) { offset -> get(strides.index(offset)) }
}
override fun NDStructure<T>.map(transform: C.(T) -> T): NDBuffer<T> {
override fun NDStructure<T>.map(transform: A.(T) -> T): NDBuffer<T> {
val buffer = bufferFactory(strides.linearSize) { offset ->
elementContext.transform(buffer[offset])
}
return NDBuffer(strides, buffer)
}
override fun NDStructure<T>.mapIndexed(transform: C.(index: IntArray, T) -> T): NDBuffer<T> {
override fun NDStructure<T>.mapIndexed(transform: A.(index: IntArray, T) -> T): NDBuffer<T> {
val buffer = bufferFactory(strides.linearSize) { offset ->
elementContext.transform(
strides.index(offset),
@ -47,7 +44,7 @@ public interface BufferNDAlgebra<T, C> : NDAlgebra<T, C> {
return NDBuffer(strides, buffer)
}
override fun combine(a: NDStructure<T>, b: NDStructure<T>, transform: C.(T, T) -> T): NDBuffer<T> {
override fun combine(a: NDStructure<T>, b: NDStructure<T>, transform: A.(T, T) -> T): NDBuffer<T> {
val buffer = bufferFactory(strides.linearSize) { offset ->
elementContext.transform(a.buffer[offset], b.buffer[offset])
}
@ -55,13 +52,14 @@ public interface BufferNDAlgebra<T, C> : NDAlgebra<T, C> {
}
}
public open class BufferedNDSpace<T, R : Space<T>>(
public open class BufferedNDSpace<T, A : Space<T>>(
final override val shape: IntArray,
final override val elementContext: R,
final override val elementContext: A,
final override val bufferFactory: BufferFactory<T>,
) : NDSpace<T, R>, BufferNDAlgebra<T, R> {
) : NDSpace<T, A>, BufferNDAlgebra<T, A> {
override val strides: Strides = DefaultStrides(shape)
override val zero: NDBuffer<T> by lazy { produce { zero } }
override fun NDStructure<T>.unaryMinus(): NDStructure<T> = produce { -get(it) }
}
public open class BufferedNDRing<T, R : Ring<T>>(
@ -76,7 +74,10 @@ public open class BufferedNDField<T, R : Field<T>>(
shape: IntArray,
elementContext: R,
bufferFactory: BufferFactory<T>,
) : BufferedNDRing<T, R>(shape, elementContext, bufferFactory), NDField<T, R>
) : BufferedNDRing<T, R>(shape, elementContext, bufferFactory), NDField<T, R> {
override fun scale(a: NDStructure<T>, value: Double): NDStructure<T> = a.map { it * value }
}
// space factories
public fun <T, A : Space<T>> NDAlgebra.Companion.space(

View File

@ -1,8 +1,6 @@
package space.kscience.kmath.nd
import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.Space
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.*
/**
@ -21,7 +19,7 @@ public class ShapeMismatchException(public val expected: IntArray, public val ac
* @param C the type of the element context.
* @param N the type of the structure.
*/
public interface NDAlgebra<T, C> {
public interface NDAlgebra<T, C: Algebra<T>> {
/**
* The shape of ND-structures this algebra operates on.
*/
@ -33,7 +31,7 @@ public interface NDAlgebra<T, C> {
public val elementContext: C
/**
* Produces a new [N] structure using given initializer function.
* Produces a new NDStructure using given initializer function.
*/
public fun produce(initializer: C.(IntArray) -> T): NDStructure<T>
@ -67,7 +65,7 @@ public interface NDAlgebra<T, C> {
* @param structures the structures to check.
* @return the array of valid structures.
*/
internal fun <T, C> NDAlgebra<T, C>.checkShape(vararg structures: NDStructure<T>): Array<out NDStructure<T>> = structures
internal fun <T, C: Algebra<T>> NDAlgebra<T, C>.checkShape(vararg structures: NDStructure<T>): Array<out NDStructure<T>> = structures
.map(NDStructure<T>::shape)
.singleOrNull { !shape.contentEquals(it) }
?.let<IntArray, Array<out NDStructure<T>>> { throw ShapeMismatchException(shape, it) }
@ -79,7 +77,7 @@ internal fun <T, C> NDAlgebra<T, C>.checkShape(vararg structures: NDStructure<T>
* @param element the structure to check.
* @return the valid structure.
*/
internal fun <T, C> NDAlgebra<T, C>.checkShape(element: NDStructure<T>): NDStructure<T> {
internal fun <T, C: Algebra<T>> NDAlgebra<T, C>.checkShape(element: NDStructure<T>): NDStructure<T> {
if (!element.shape.contentEquals(shape)) throw ShapeMismatchException(shape, element.shape)
return element
}
@ -102,14 +100,14 @@ public interface NDSpace<T, S : Space<T>> : Space<NDStructure<T>>, NDAlgebra<T,
public override fun add(a: NDStructure<T>, b: NDStructure<T>): NDStructure<T> =
combine(a, b) { aValue, bValue -> add(aValue, bValue) }
/**
* Element-wise multiplication by scalar.
*
* @param a the multiplicand.
* @param k the multiplier.
* @return the product.
*/
public override fun multiply(a: NDStructure<T>, k: Number): NDStructure<T> = a.map() { multiply(it, k) }
// /**
// * Element-wise multiplication by scalar.
// *
// * @param a the multiplicand.
// * @param k the multiplier.
// * @return the product.
// */
// public override fun multiply(a: NDStructure<T>, k: Number): NDStructure<T> = a.map { multiply(it, k) }
// TODO move to extensions after KEEP-176
@ -120,7 +118,7 @@ public interface NDSpace<T, S : Space<T>> : Space<NDStructure<T>>, NDAlgebra<T,
* @param arg the augend.
* @return the sum.
*/
public operator fun NDStructure<T>.plus(arg: T): NDStructure<T> = this.map() { value -> add(arg, value) }
public operator fun NDStructure<T>.plus(arg: T): NDStructure<T> = this.map { value -> add(arg, value) }
/**
* Subtracts an element from ND structure of it.
@ -200,7 +198,7 @@ public interface NDRing<T, R : Ring<T>> : Ring<NDStructure<T>>, NDSpace<T, R> {
* @param N the type of ND structure.
* @param F the type field of structure elements.
*/
public interface NDField<T, F : Field<T>> : Field<NDStructure<T>>, NDRing<T, F> {
public interface NDField<T, F : Field<T>> : Field<NDStructure<T>>, NDRing<T, F>, ScaleOperations<NDStructure<T>> {
/**
* Element-wise division.
*

View File

@ -2,8 +2,9 @@ package space.kscience.kmath.nd
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.NumbersAddOperations
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.RingWithNumbers
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.RealBuffer
import kotlin.contracts.InvocationKind
@ -13,7 +14,8 @@ import kotlin.contracts.contract
public class RealNDField(
shape: IntArray,
) : BufferedNDField<Double, RealField>(shape, RealField, Buffer.Companion::real),
RingWithNumbers<NDStructure<Double>>,
NumbersAddOperations<NDStructure<Double>>,
ScaleOperations<NDStructure<Double>>,
ExtendedField<NDStructure<Double>> {
override val zero: NDBuffer<Double> by lazy { produce { zero } }
@ -75,6 +77,8 @@ public class RealNDField(
return NDBuffer(strides, buffer)
}
override fun scale(a: NDStructure<Double>, value: Double): NDStructure<Double> = a.map { it * value }
override fun power(arg: NDStructure<Double>, pow: Number): NDBuffer<Double> = arg.map { power(it, pow) }
override fun exp(arg: NDStructure<Double>): NDBuffer<Double> = arg.map { exp(it) }

View File

@ -1,7 +1,7 @@
package space.kscience.kmath.nd
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.RingWithNumbers
import space.kscience.kmath.operations.NumbersAddOperations
import space.kscience.kmath.operations.ShortRing
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.ShortBuffer
@ -12,7 +12,7 @@ import kotlin.contracts.contract
public class ShortNDRing(
shape: IntArray,
) : BufferedNDRing<Short, ShortRing>(shape, ShortRing, Buffer.Companion::auto),
RingWithNumbers<NDStructure<Short>> {
NumbersAddOperations<NDStructure<Short>> {
override val zero: NDBuffer<Short> by lazy { produce { zero } }
override val one: NDBuffer<Short> by lazy { produce { one } }

View File

@ -87,7 +87,8 @@ public interface Algebra<T> {
* @param right the second argument of operation.
* @return a result of operation.
*/
public fun binaryOperation(operation: String, left: T, right: T): T = binaryOperationFunction(operation)(left, right)
public fun binaryOperation(operation: String, left: T, right: T): T =
binaryOperationFunction(operation)(left, right)
}
public fun <T : Any> Algebra<T>.bindSymbol(symbol: Symbol): T = bindSymbol(symbol.identity)
@ -114,15 +115,6 @@ public interface SpaceOperations<T> : Algebra<T> {
*/
public fun add(a: T, b: T): T
/**
* Multiplication of element by scalar.
*
* @param a the multiplier.
* @param k the multiplicand.
* @return the produce.
*/
public fun multiply(a: T, k: Number): T
// Operations to be performed in this context. Could be moved to extensions in case of KEEP-176
/**
@ -131,7 +123,7 @@ public interface SpaceOperations<T> : Algebra<T> {
* @receiver this value.
* @return the additive inverse of this value.
*/
public operator fun T.unaryMinus(): T = multiply(this, -1.0)
public operator fun T.unaryMinus(): T
/**
* Returns this value.
@ -159,34 +151,6 @@ public interface SpaceOperations<T> : Algebra<T> {
*/
public operator fun T.minus(b: T): T = add(this, -b)
/**
* Multiplication of this element by a scalar.
*
* @receiver the multiplier.
* @param k the multiplicand.
* @return the product.
*/
public operator fun T.times(k: Number): T = multiply(this, k)
/**
* Division of this element by scalar.
*
* @receiver the dividend.
* @param k the divisor.
* @return the quotient.
*/
@Deprecated("Dividing not allowed in a Ring")
public operator fun T.div(k: Number): T = multiply(this, 1.0 / k.toDouble())
/**
* Multiplication of this number by element.
*
* @receiver the multiplier.
* @param b the multiplicand.
* @return the product.
*/
public operator fun Number.times(b: T): T = b * this
public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) {
PLUS_OPERATION -> { arg -> arg }
MINUS_OPERATION -> { arg -> -arg }
@ -318,13 +282,6 @@ public interface FieldOperations<T> : RingOperations<T> {
*
* @param T the type of element of this semifield.
*/
public interface Field<T> : Ring<T>, FieldOperations<T> {
/**
* Division of element by scalar.
*
* @receiver the dividend.
* @param b the divisor.
* @return the quotient.
*/
public operator fun Number.div(b: T): T = this * divide(one, b)
public interface Field<T> : Ring<T>, FieldOperations<T>, ScaleOperations<T>, NumericAlgebra<T> {
override fun number(value: Number): T = scale(one, value.toDouble())
}

View File

@ -14,24 +14,24 @@ public interface AlgebraElement<T, C : Algebra<T>> {
*/
public val context: C
}
/**
* Divides this element by number.
*
* @param k the divisor.
* @return the quotient.
*/
public operator fun <T : AlgebraElement<T, S>, S : Space<T>> T.div(k: Number): T =
context.multiply(this, 1.0 / k.toDouble())
/**
* Multiplies this element by number.
*
* @param k the multiplicand.
* @return the product.
*/
public operator fun <T : AlgebraElement<T, S>, S : Space<T>> T.times(k: Number): T =
context.multiply(this, k.toDouble())
//
///**
// * Divides this element by number.
// *
// * @param k the divisor.
// * @return the quotient.
// */
//public operator fun <T : AlgebraElement<T, S>, S : Space<T>> T.div(k: Number): T =
// context.multiply(this, 1.0 / k.toDouble())
//
///**
// * Multiplies this element by number.
// *
// * @param k the multiplicand.
// * @return the product.
// */
//public operator fun <T : AlgebraElement<T, S>, S : Space<T>> T.times(k: Number): T =
// context.multiply(this, k.toDouble())
/**
* Subtracts element from this one.
@ -39,8 +39,9 @@ public operator fun <T : AlgebraElement<T, S>, S : Space<T>> T.times(k: Number):
* @param b the subtrahend.
* @return the difference.
*/
public operator fun <T : AlgebraElement<T, S>, S : Space<T>> T.minus(b: T): T =
context.add(this, context.multiply(b, -1.0))
@UnstableKMathAPI
public operator fun <T : AlgebraElement<T, S>, S : NumbersAddOperations<T>> T.minus(b: T): T =
context.add(this, context.run { -b})
/**
* Adds element to this one.
@ -51,11 +52,11 @@ public operator fun <T : AlgebraElement<T, S>, S : Space<T>> T.minus(b: T): T =
public operator fun <T : AlgebraElement<T, S>, S : Space<T>> T.plus(b: T): T =
context.add(this, b)
/**
* Number times element
*/
public operator fun <T : AlgebraElement<T, S>, S : Space<T>> Number.times(element: T): T =
element.times(this)
///**
// * Number times element
// */
//public operator fun <T : AlgebraElement<T, S>, S : Space<T>> Number.times(element: T): T =
// element.times(this)
/**

View File

@ -21,28 +21,27 @@ public typealias TBase = ULong
* @author Robert Drynkin (https://github.com/robdrynkin) and Peter Klimai (https://github.com/pklimai)
*/
@OptIn(UnstableKMathAPI::class)
public object BigIntField : Field<BigInt>, RingWithNumbers<BigInt> {
public object BigIntField : Field<BigInt>, NumbersAddOperations<BigInt>, ScaleOperations<BigInt> {
override val zero: BigInt = BigInt.ZERO
override val one: BigInt = BigInt.ONE
override fun add(a: BigInt, b: BigInt): BigInt = a.plus(b)
override fun number(value: Number): BigInt = value.toLong().toBigInt()
override fun multiply(a: BigInt, k: Number): BigInt = a.times(number(k))
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
override fun BigInt.unaryMinus(): BigInt = -this
override fun add(a: BigInt, b: BigInt): BigInt = a.plus(b)
override fun scale(a: BigInt, value: Double): BigInt = a.times(number(value))
override fun multiply(a: BigInt, b: BigInt): BigInt = a.times(b)
override fun divide(a: BigInt, b: BigInt): BigInt = a.div(b)
public operator fun String.unaryPlus(): BigInt = this.parseBigInteger() ?: error("Can't parse $this as big integer")
public operator fun String.unaryMinus(): BigInt =
-(this.parseBigInteger() ?: error("Can't parse $this as big integer"))
override fun divide(a: BigInt, b: BigInt): BigInt = a.div(b)
}
public class BigInt internal constructor(
private val sign: Byte,
private val magnitude: Magnitude
private val magnitude: Magnitude,
) : Comparable<BigInt> {
public override fun compareTo(other: BigInt): Int = when {
(sign == 0.toByte()) and (other.sign == 0.toByte()) -> 0

View File

@ -81,14 +81,53 @@ public interface NumericAlgebra<T> : Algebra<T> {
rightSideNumberOperationFunction(operation)(left, right)
}
/**
* Scale by scalar operations
*/
public interface ScaleOperations<T> : Algebra<T> {
/**
* Scaling of element by scalar.
*
* @param a the multiplier.
* @param value the multiplicand.
* @return the produce.
*/
public fun scale(a: T, value: Double): T
/**
* Multiplication of this element by a scalar.
*
* @receiver the multiplier.
* @param k the multiplicand.
* @return the product.
*/
public operator fun T.times(k: Number): T = scale(this, k.toDouble())
/**
* Division of this element by scalar.
*
* @receiver the dividend.
* @param k the divisor.
* @return the quotient.
*/
public operator fun T.div(k: Number): T = scale(this, 1.0 / k.toDouble())
/**
* Multiplication of this number by element.
*
* @receiver the multiplier.
* @param b the multiplicand.
* @return the product.
*/
public operator fun Number.times(b: T): T = b * this
}
/**
* A combination of [NumericAlgebra] and [Ring] that adds intrinsic simple operations on numbers like `T+1`
* TODO to be removed and replaced by extensions after multiple receivers are there
*/
@UnstableKMathAPI
public interface RingWithNumbers<T>: Ring<T>, NumericAlgebra<T>{
public override fun number(value: Number): T = one * value
public interface NumbersAddOperations<T> : Space<T>, NumericAlgebra<T> {
/**
* Addition of element and scalar.
*

View File

@ -107,111 +107,6 @@ public fun <T : AlgebraElement<T, out TrigonometricOperations<T>>> acos(arg: T):
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out TrigonometricOperations<T>>> atan(arg: T): T = arg.context.atan(arg)
/**
* A container for hyperbolic trigonometric operations for specific type.
*
* @param T the type of element of this structure.
*/
public interface HyperbolicOperations<T> : Algebra<T> {
/**
* Computes the hyperbolic sine of [arg].
*/
public fun sinh(arg: T): T
/**
* Computes the hyperbolic cosine of [arg].
*/
public fun cosh(arg: T): T
/**
* Computes the hyperbolic tangent of [arg].
*/
public fun tanh(arg: T): T
/**
* Computes the inverse hyperbolic sine of [arg].
*/
public fun asinh(arg: T): T
/**
* Computes the inverse hyperbolic cosine of [arg].
*/
public fun acosh(arg: T): T
/**
* Computes the inverse hyperbolic tangent of [arg].
*/
public fun atanh(arg: T): T
public companion object {
/**
* The identifier of hyperbolic sine.
*/
public const val SINH_OPERATION: String = "sinh"
/**
* The identifier of hyperbolic cosine.
*/
public const val COSH_OPERATION: String = "cosh"
/**
* The identifier of hyperbolic tangent.
*/
public const val TANH_OPERATION: String = "tanh"
/**
* The identifier of inverse hyperbolic sine.
*/
public const val ASINH_OPERATION: String = "asinh"
/**
* The identifier of inverse hyperbolic cosine.
*/
public const val ACOSH_OPERATION: String = "acosh"
/**
* The identifier of inverse hyperbolic tangent.
*/
public const val ATANH_OPERATION: String = "atanh"
}
}
/**
* Computes the hyperbolic sine of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out HyperbolicOperations<T>>> sinh(arg: T): T = arg.context.sinh(arg)
/**
* Computes the hyperbolic cosine of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out HyperbolicOperations<T>>> cosh(arg: T): T = arg.context.cosh(arg)
/**
* Computes the hyperbolic tangent of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out HyperbolicOperations<T>>> tanh(arg: T): T = arg.context.tanh(arg)
/**
* Computes the inverse hyperbolic sine of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out HyperbolicOperations<T>>> asinh(arg: T): T = arg.context.asinh(arg)
/**
* Computes the inverse hyperbolic cosine of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out HyperbolicOperations<T>>> acosh(arg: T): T = arg.context.acosh(arg)
/**
* Computes the inverse hyperbolic tangent of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out HyperbolicOperations<T>>> atanh(arg: T): T = arg.context.atanh(arg)
/**
* A context extension to include power operations based on exponentiation.
*
@ -284,6 +179,36 @@ public interface ExponentialOperations<T> : Algebra<T> {
*/
public fun ln(arg: T): T
/**
* Computes the hyperbolic sine of [arg].
*/
public fun sinh(arg: T): T
/**
* Computes the hyperbolic cosine of [arg].
*/
public fun cosh(arg: T): T
/**
* Computes the hyperbolic tangent of [arg].
*/
public fun tanh(arg: T): T
/**
* Computes the inverse hyperbolic sine of [arg].
*/
public fun asinh(arg: T): T
/**
* Computes the inverse hyperbolic cosine of [arg].
*/
public fun acosh(arg: T): T
/**
* Computes the inverse hyperbolic tangent of [arg].
*/
public fun atanh(arg: T): T
public companion object {
/**
* The identifier of exponential function.
@ -294,6 +219,36 @@ public interface ExponentialOperations<T> : Algebra<T> {
* The identifier of natural logarithm.
*/
public const val LN_OPERATION: String = "ln"
/**
* The identifier of hyperbolic sine.
*/
public const val SINH_OPERATION: String = "sinh"
/**
* The identifier of hyperbolic cosine.
*/
public const val COSH_OPERATION: String = "cosh"
/**
* The identifier of hyperbolic tangent.
*/
public const val TANH_OPERATION: String = "tanh"
/**
* The identifier of inverse hyperbolic sine.
*/
public const val ASINH_OPERATION: String = "asinh"
/**
* The identifier of inverse hyperbolic cosine.
*/
public const val ACOSH_OPERATION: String = "acosh"
/**
* The identifier of inverse hyperbolic tangent.
*/
public const val ATANH_OPERATION: String = "atanh"
}
}
@ -309,6 +264,43 @@ public fun <T : AlgebraElement<T, out ExponentialOperations<T>>> exp(arg: T): T
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out ExponentialOperations<T>>> ln(arg: T): T = arg.context.ln(arg)
/**
* Computes the hyperbolic sine of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out ExponentialOperations<T>>> sinh(arg: T): T = arg.context.sinh(arg)
/**
* Computes the hyperbolic cosine of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out ExponentialOperations<T>>> cosh(arg: T): T = arg.context.cosh(arg)
/**
* Computes the hyperbolic tangent of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out ExponentialOperations<T>>> tanh(arg: T): T = arg.context.tanh(arg)
/**
* Computes the inverse hyperbolic sine of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out ExponentialOperations<T>>> asinh(arg: T): T = arg.context.asinh(arg)
/**
* Computes the inverse hyperbolic cosine of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out ExponentialOperations<T>>> acosh(arg: T): T = arg.context.acosh(arg)
/**
* Computes the inverse hyperbolic tangent of [arg].
*/
@UnstableKMathAPI
public fun <T : AlgebraElement<T, out ExponentialOperations<T>>> atanh(arg: T): T = arg.context.atanh(arg)
/**
* A container for norm functional on element.
*

View File

@ -26,7 +26,8 @@ public fun <T> Space<T>.sum(data: Sequence<T>): T = data.fold(zero) { left, righ
* @return the average value.
* @author Iaroslav Postovalov
*/
public fun <T> Space<T>.average(data: Iterable<T>): T = sum(data) / data.count()
public fun <T, S> S.average(data: Iterable<T>): T where S : Space<T>, S : ScaleOperations<T> =
sum(data) / data.count()
/**
* Returns an average value of elements in the sequence in this [Space].
@ -36,7 +37,8 @@ public fun <T> Space<T>.average(data: Iterable<T>): T = sum(data) / data.count()
* @return the average value.
* @author Iaroslav Postovalov
*/
public fun <T> Space<T>.average(data: Sequence<T>): T = sum(data) / data.count()
public fun <T, S> S.average(data: Sequence<T>): T where S : Space<T>, S : ScaleOperations<T> =
sum(data) / data.count()
/**
* Absolute of the comparable [value]
@ -69,7 +71,8 @@ public fun <T> Sequence<T>.sumWith(space: Space<T>): T = space.sum(this)
* @return the average value.
* @author Iaroslav Postovalov
*/
public fun <T> Iterable<T>.averageWith(space: Space<T>): T = space.average(this)
public fun <T, S> Iterable<T>.averageWith(space: S): T where S : Space<T>, S : ScaleOperations<T> =
space.average(this)
/**
* Returns an average value of elements in the sequence in this [Space].
@ -79,7 +82,8 @@ public fun <T> Iterable<T>.averageWith(space: Space<T>): T = space.average(this)
* @return the average value.
* @author Iaroslav Postovalov
*/
public fun <T> Sequence<T>.averageWith(space: Space<T>): T = space.average(this)
public fun <T, S> Sequence<T>.averageWith(space: S): T where S : Space<T>, S : ScaleOperations<T> =
space.average(this)
//TODO optimized power operation

View File

@ -8,7 +8,6 @@ import kotlin.math.pow as kpow
public interface ExtendedFieldOperations<T> :
FieldOperations<T>,
TrigonometricOperations<T>,
HyperbolicOperations<T>,
PowerOperations<T>,
ExponentialOperations<T> {
public override fun tan(arg: T): T = sin(arg) / cos(arg)
@ -21,15 +20,15 @@ public interface ExtendedFieldOperations<T> :
TrigonometricOperations.ACOS_OPERATION -> ::acos
TrigonometricOperations.ASIN_OPERATION -> ::asin
TrigonometricOperations.ATAN_OPERATION -> ::atan
HyperbolicOperations.COSH_OPERATION -> ::cosh
HyperbolicOperations.SINH_OPERATION -> ::sinh
HyperbolicOperations.TANH_OPERATION -> ::tanh
HyperbolicOperations.ACOSH_OPERATION -> ::acosh
HyperbolicOperations.ASINH_OPERATION -> ::asinh
HyperbolicOperations.ATANH_OPERATION -> ::atanh
PowerOperations.SQRT_OPERATION -> ::sqrt
ExponentialOperations.EXP_OPERATION -> ::exp
ExponentialOperations.LN_OPERATION -> ::ln
ExponentialOperations.COSH_OPERATION -> ::cosh
ExponentialOperations.SINH_OPERATION -> ::sinh
ExponentialOperations.TANH_OPERATION -> ::tanh
ExponentialOperations.ACOSH_OPERATION -> ::acosh
ExponentialOperations.ASINH_OPERATION -> ::asinh
ExponentialOperations.ATANH_OPERATION -> ::atanh
else -> super<FieldOperations>.unaryOperationFunction(operation)
}
}
@ -37,18 +36,18 @@ public interface ExtendedFieldOperations<T> :
/**
* Advanced Number-like field that implements basic operations.
*/
public interface ExtendedField<T> : ExtendedFieldOperations<T>, Field<T>, NumericAlgebra<T> {
public override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2
public override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2
public interface ExtendedField<T> : ExtendedFieldOperations<T>, Field<T>, NumericAlgebra<T>, ScaleOperations<T> {
public override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0
public override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0
public override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg))
public override fun asinh(arg: T): T = ln(sqrt(arg * arg + one) + arg)
public override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one)))
public override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2
public override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2.0
public override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T =
when (operation) {
PowerOperations.POW_OPERATION -> ::power
else -> super.rightSideNumberOperationFunction(operation)
else -> super<Field>.rightSideNumberOperationFunction(operation)
}
}
@ -56,28 +55,27 @@ public interface ExtendedField<T> : ExtendedFieldOperations<T>, Field<T>, Numeri
* A field for [Double] without boxing. Does not produce appropriate field element.
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public object RealField : ExtendedField<Double>, Norm<Double, Double> {
public override val zero: Double
get() = 0.0
public override val one: Double
get() = 1.0
public object RealField : ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double> {
public override val zero: Double = 0.0
public override val one: Double = 1.0
override fun number(value: Number): Double = value.toDouble()
public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double =
when (operation) {
PowerOperations.POW_OPERATION -> ::power
else -> super.binaryOperationFunction(operation)
else -> super<ExtendedField>.binaryOperationFunction(operation)
}
public override inline fun add(a: Double, b: Double): Double = a + b
public override inline fun multiply(a: Double, k: Number): Double = a * k.toDouble()
// public override inline fun multiply(a: Double, k: Number): Double = a * k.toDouble()
// override fun divide(a: Double, k: Number): Double = a / k.toDouble()
public override inline fun multiply(a: Double, b: Double): Double = a * b
public override inline fun divide(a: Double, b: Double): Double = a / b
override fun scale(a: Double, value: Double): Double = a * value
public override inline fun sin(arg: Double): Double = kotlin.math.sin(arg)
public override inline fun cos(arg: Double): Double = kotlin.math.cos(arg)
public override inline fun tan(arg: Double): Double = kotlin.math.tan(arg)
@ -110,11 +108,8 @@ public object RealField : ExtendedField<Double>, Norm<Double, Double> {
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public object FloatField : ExtendedField<Float>, Norm<Float, Float> {
public override val zero: Float
get() = 0.0f
public override val one: Float
get() = 1.0f
public override val zero: Float = 0.0f
public override val one: Float = 1.0f
override fun number(value: Number): Float = value.toFloat()
@ -125,7 +120,7 @@ public object FloatField : ExtendedField<Float>, Norm<Float, Float> {
}
public override inline fun add(a: Float, b: Float): Float = a + b
public override inline fun multiply(a: Float, k: Number): Float = a * k.toFloat()
override fun scale(a: Float, value: Double): Float = a * value.toFloat()
public override inline fun multiply(a: Float, b: Float): Float = a * b
@ -170,12 +165,8 @@ public object IntRing : Ring<Int>, Norm<Int, Int>, NumericAlgebra<Int> {
get() = 1
override fun number(value: Number): Int = value.toInt()
public override inline fun add(a: Int, b: Int): Int = a + b
public override inline fun multiply(a: Int, k: Number): Int = k.toInt() * a
public override inline fun multiply(a: Int, b: Int): Int = a * b
public override inline fun norm(arg: Int): Int = abs(arg)
public override inline fun Int.unaryMinus(): Int = -this
@ -196,12 +187,8 @@ public object ShortRing : Ring<Short>, Norm<Short, Short>, NumericAlgebra<Short>
get() = 1
override fun number(value: Number): Short = value.toShort()
public override inline fun add(a: Short, b: Short): Short = (a + b).toShort()
public override inline fun multiply(a: Short, k: Number): Short = (a * k.toShort()).toShort()
public override inline fun multiply(a: Short, b: Short): Short = (a * b).toShort()
public override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort()
public override inline fun Short.unaryMinus(): Short = (-this).toShort()
@ -222,12 +209,8 @@ public object ByteRing : Ring<Byte>, Norm<Byte, Byte>, NumericAlgebra<Byte> {
get() = 1
override fun number(value: Number): Byte = value.toByte()
public override inline fun add(a: Byte, b: Byte): Byte = (a + b).toByte()
public override inline fun multiply(a: Byte, k: Number): Byte = (a * k.toByte()).toByte()
public override inline fun multiply(a: Byte, b: Byte): Byte = (a * b).toByte()
public override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte()
public override inline fun Byte.unaryMinus(): Byte = (-this).toByte()
@ -248,12 +231,8 @@ public object LongRing : Ring<Long>, Norm<Long, Long>, NumericAlgebra<Long> {
get() = 1L
override fun number(value: Number): Long = value.toLong()
public override inline fun add(a: Long, b: Long): Long = a + b
public override inline fun multiply(a: Long, k: Number): Long = a * k.toLong()
public override inline fun multiply(a: Long, b: Long): Long = a * b
public override fun norm(arg: Long): Long = abs(arg)
public override inline fun Long.unaryMinus(): Long = (-this)

View File

@ -8,6 +8,12 @@ import kotlin.math.*
* [ExtendedFieldOperations] over [RealBuffer].
*/
public object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
override fun Buffer<Double>.unaryMinus(): RealBuffer = if (this is RealBuffer) {
RealBuffer(size) { -array[it] }
} else {
RealBuffer(size) { -get(it) }
}
public override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(b.size == a.size) {
"The size of the first buffer ${a.size} should be the same as for second one: ${b.size} "
@ -19,15 +25,24 @@ public object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>
RealBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] })
} else RealBuffer(DoubleArray(a.size) { a[it] + b[it] })
}
public override fun multiply(a: Buffer<Double>, k: Number): RealBuffer {
val kValue = k.toDouble()
return if (a is RealBuffer) {
val aArray = a.array
RealBuffer(DoubleArray(a.size) { aArray[it] * kValue })
} else RealBuffer(DoubleArray(a.size) { a[it] * kValue })
}
//
// public override fun multiply(a: Buffer<Double>, k: Number): RealBuffer {
// val kValue = k.toDouble()
//
// return if (a is RealBuffer) {
// val aArray = a.array
// RealBuffer(DoubleArray(a.size) { aArray[it] * kValue })
// } else RealBuffer(DoubleArray(a.size) { a[it] * kValue })
// }
//
// public override fun divide(a: Buffer<Double>, k: Number): RealBuffer {
// val kValue = k.toDouble()
//
// return if (a is RealBuffer) {
// val aArray = a.array
// RealBuffer(DoubleArray(a.size) { aArray[it] / kValue })
// } else RealBuffer(DoubleArray(a.size) { a[it] / kValue })
// }
public override fun multiply(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(b.size == a.size) {
@ -152,14 +167,22 @@ public class RealBufferField(public val size: Int) : ExtendedField<Buffer<Double
override fun number(value: Number): Buffer<Double> = RealBuffer(size) { value.toDouble() }
override fun Buffer<Double>.unaryMinus(): Buffer<Double> = RealBufferFieldOperations.run {
-this@unaryMinus
}
public override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
return RealBufferFieldOperations.add(a, b)
}
public override fun multiply(a: Buffer<Double>, k: Number): RealBuffer {
public override fun scale(a: Buffer<Double>, value: Double): RealBuffer {
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
return RealBufferFieldOperations.multiply(a, k)
return if (a is RealBuffer) {
val aArray = a.array
RealBuffer(DoubleArray(a.size) { aArray[it] * value })
} else RealBuffer(DoubleArray(a.size) { a[it] * value })
}
public override fun multiply(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {

View File

@ -11,9 +11,7 @@ class ExpressionFieldTest {
@Test
fun testExpression() {
val context = FunctionalExpressionField(RealField)
val expression = context {
val expression = FunctionalExpressionField(RealField).invoke {
val x by binding()
x * x + 2 * x + one
}

View File

@ -5,8 +5,9 @@ import space.kscience.kmath.operations.invoke
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
internal class FieldVerifier<T>(override val algebra: Field<T>, a: T, b: T, c: T, x: Number) :
RingVerifier<T>(algebra, a, b, c, x) {
internal class FieldVerifier<T, A : Field<T>>(
algebra: A, a: T, b: T, c: T, x: Number,
) : RingVerifier<T, A>(algebra, a, b, c, x) {
override fun verify() {
super.verify()

View File

@ -1,11 +1,13 @@
package space.kscience.kmath.testutils
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.invoke
import kotlin.test.assertEquals
internal open class RingVerifier<T>(override val algebra: Ring<T>, a: T, b: T, c: T, x: Number) :
SpaceVerifier<T>(algebra, a, b, c, x) {
internal open class RingVerifier<T, A>(algebra: A, a: T, b: T, c: T, x: Number) :
SpaceVerifier<T, A>(algebra, a, b, c, x) where A : Ring<T>, A : ScaleOperations<T> {
override fun verify() {
super.verify()

View File

@ -1,18 +1,18 @@
package space.kscience.kmath.testutils
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.Space
import space.kscience.kmath.operations.invoke
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
internal open class SpaceVerifier<T>(
override val algebra: Space<T>,
internal open class SpaceVerifier<T, out S>(
override val algebra: S,
val a: T,
val b: T,
val c: T,
val x: Number
) :
AlgebraicVerifier<T, Space<T>> {
val x: Number,
) : AlgebraicVerifier<T, Space<T>> where S : Space<T>, S : ScaleOperations<T> {
override fun verify() {
algebra {
assertEquals(a + b + c, a + (b + c), "Addition in $algebra is not associative.")

View File

@ -7,19 +7,16 @@ import java.math.MathContext
/**
* A field over [BigInteger].
*/
public object JBigIntegerField : Field<BigInteger>, NumericAlgebra<BigInteger> {
public override val zero: BigInteger
get() = BigInteger.ZERO
public object JBigIntegerField : Ring<BigInteger>, NumericAlgebra<BigInteger> {
public override val zero: BigInteger get() = BigInteger.ZERO
public override val one: BigInteger
get() = BigInteger.ONE
public override val one: BigInteger get() = BigInteger.ONE
public override fun number(value: Number): BigInteger = BigInteger.valueOf(value.toLong())
public override fun divide(a: BigInteger, b: BigInteger): BigInteger = a.div(b)
public override fun add(a: BigInteger, b: BigInteger): BigInteger = a.add(b)
public override operator fun BigInteger.minus(b: BigInteger): BigInteger = subtract(b)
public override fun multiply(a: BigInteger, k: Number): BigInteger = a.multiply(k.toInt().toBigInteger())
public override fun multiply(a: BigInteger, b: BigInteger): BigInteger = a.multiply(b)
public override operator fun BigInteger.unaryMinus(): BigInteger = negate()
}
@ -30,7 +27,7 @@ public object JBigIntegerField : Field<BigInteger>, NumericAlgebra<BigInteger> {
*/
public abstract class JBigDecimalFieldBase internal constructor(
private val mathContext: MathContext = MathContext.DECIMAL64,
) : Field<BigDecimal>, PowerOperations<BigDecimal>, NumericAlgebra<BigDecimal> {
) : Field<BigDecimal>, PowerOperations<BigDecimal>, NumericAlgebra<BigDecimal>, ScaleOperations<BigDecimal> {
public override val zero: BigDecimal
get() = BigDecimal.ZERO
@ -41,8 +38,8 @@ public abstract class JBigDecimalFieldBase internal constructor(
public override operator fun BigDecimal.minus(b: BigDecimal): BigDecimal = subtract(b)
public override fun number(value: Number): BigDecimal = BigDecimal.valueOf(value.toDouble())
public override fun multiply(a: BigDecimal, k: Number): BigDecimal =
a.multiply(k.toDouble().toBigDecimal(mathContext), mathContext)
public override fun scale(a: BigDecimal, value: Double): BigDecimal =
a.multiply(value.toBigDecimal(mathContext), mathContext)
public override fun multiply(a: BigDecimal, b: BigDecimal): BigDecimal = a.multiply(b, mathContext)
public override fun divide(a: BigDecimal, b: BigDecimal): BigDecimal = a.divide(b, mathContext)

View File

@ -5,16 +5,16 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.runningReduce
import kotlinx.coroutines.flow.scan
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.Space
import space.kscience.kmath.operations.SpaceOperations
import space.kscience.kmath.operations.invoke
@ExperimentalCoroutinesApi
public fun <T> Flow<T>.cumulativeSum(space: SpaceOperations<T>): Flow<T> =
space { runningReduce { sum, element -> sum + element } }
@ExperimentalCoroutinesApi
public fun <T> Flow<T>.mean(space: Space<T>): Flow<T> = space {
public fun <T, S> Flow<T>.mean(algebra: S): Flow<T> where S : Space<T>, S : ScaleOperations<T> = algebra {
data class Accumulator(var sum: T, var num: Int)
scan(Accumulator(zero, 0)) { sum, element ->

View File

@ -4,13 +4,14 @@ import org.ejml.simple.SimpleMatrix
import space.kscience.kmath.linear.*
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.getFeature
import space.kscience.kmath.operations.ScaleOperations
/**
* Represents context of basic operations operating with [EjmlMatrix].
*
* @author Iaroslav Postovalov
*/
public object EjmlMatrixContext : MatrixContext<Double, EjmlMatrix> {
public object EjmlMatrixContext : MatrixContext<Double, EjmlMatrix>, ScaleOperations<Matrix<Double>> {
/**
* Converts this matrix to EJML one.
@ -41,6 +42,9 @@ public object EjmlMatrixContext : MatrixContext<Double, EjmlMatrix> {
(0 until it.numRows()).forEach { row -> it[row, 0] = initializer(row) }
})
override fun Matrix<Double>.unaryMinus(): Matrix<Double> = this*(-1)
public override fun Matrix<Double>.dot(other: Matrix<Double>): EjmlMatrix =
EjmlMatrix(toEjml().origin.mult(other.toEjml().origin))
@ -53,8 +57,8 @@ public object EjmlMatrixContext : MatrixContext<Double, EjmlMatrix> {
public override operator fun Matrix<Double>.minus(b: Matrix<Double>): EjmlMatrix =
EjmlMatrix(toEjml().origin - b.toEjml().origin)
public override fun multiply(a: Matrix<Double>, k: Number): EjmlMatrix =
produce(a.rowNum, a.colNum) { i, j -> a[i, j] * k.toDouble() }
public override fun scale(a: Matrix<Double>, value: Double): EjmlMatrix =
produce(a.rowNum, a.colNum) { i, j -> a[i, j] * value }
public override operator fun Matrix<Double>.times(value: Double): EjmlMatrix =
EjmlMatrix(toEjml().origin.scale(value))

View File

@ -1,6 +1,7 @@
package space.kscience.kmath.functions
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.Space
import space.kscience.kmath.operations.invoke
import kotlin.contracts.InvocationKind
@ -41,9 +42,15 @@ public fun <T : Any, C : Ring<T>> Polynomial<T>.asFunction(ring: C): (T) -> T =
/**
* An algebra for polynomials
*/
public class PolynomialSpace<T : Any, C : Ring<T>>(private val ring: C) : Space<Polynomial<T>> {
public class PolynomialSpace<T : Any, C >(
private val ring: C,
) : Space<Polynomial<T>>, ScaleOperations<Polynomial<T>> where C: Ring<T>, C: ScaleOperations<T>{
public override val zero: Polynomial<T> = Polynomial(emptyList())
override fun Polynomial<T>.unaryMinus(): Polynomial<T> = with(ring) {
Polynomial(coefficients.map { -it })
}
public override fun add(a: Polynomial<T>, b: Polynomial<T>): Polynomial<T> {
val dim = max(a.coefficients.size, b.coefficients.size)
@ -54,13 +61,13 @@ public class PolynomialSpace<T : Any, C : Ring<T>>(private val ring: C) : Space<
}
}
public override fun multiply(a: Polynomial<T>, k: Number): Polynomial<T> =
ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * k }) }
public override fun scale(a: Polynomial<T>, value: Double): Polynomial<T> =
ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) }
public operator fun Polynomial<T>.invoke(arg: T): T = value(ring, arg)
}
public inline fun <T : Any, C : Ring<T>, R> C.polynomial(block: PolynomialSpace<T, C>.() -> R): R {
public inline fun <T : Any, C, R> C.polynomial(block: PolynomialSpace<T, C>.() -> R): R where C: Ring<T>, C: ScaleOperations<T>{
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return PolynomialSpace(this).block()
}

View File

@ -11,9 +11,9 @@ import space.kscience.kmath.structures.MutableBufferFactory
* Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type specific ones.
* Based on https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java
*/
public class SplineInterpolator<T : Comparable<T>>(
public override val algebra: Field<T>,
public val bufferFactory: MutableBufferFactory<T>
public class SplineInterpolator<T : Comparable<T>, F : Field<T>>(
public override val algebra: F,
public val bufferFactory: MutableBufferFactory<T>,
) : PolynomialInterpolator<T> {
//TODO possibly optimize zeroed buffers

View File

@ -2,6 +2,7 @@ package space.kscience.kmath.geometry
import space.kscience.kmath.linear.Point
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.SpaceElement
import space.kscience.kmath.operations.invoke
import kotlin.math.sqrt
@ -30,18 +31,20 @@ public fun Vector2D(x: Double, y: Double): Vector2D = Vector2DImpl(x, y)
private data class Vector2DImpl(
override val x: Double,
override val y: Double
override val y: Double,
) : Vector2D
/**
* 2D Euclidean space
*/
public object Euclidean2DSpace : GeometrySpace<Vector2D> {
public object Euclidean2DSpace : GeometrySpace<Vector2D>, ScaleOperations<Vector2D> {
public override val zero: Vector2D by lazy { Vector2D(0.0, 0.0) }
public fun Vector2D.norm(): Double = sqrt(x * x + y * y)
override fun Vector2D.unaryMinus(): Vector2D = Vector2D(-x, -y)
public override fun Vector2D.distanceTo(other: Vector2D): Double = (this - other).norm()
public override fun add(a: Vector2D, b: Vector2D): Vector2D = Vector2D(a.x + b.x, a.y + b.y)
public override fun multiply(a: Vector2D, k: Number): Vector2D = Vector2D(a.x * k.toDouble(), a.y * k.toDouble())
public override fun scale(a: Vector2D, value: Double): Vector2D = Vector2D(a.x * value, a.y * value)
public override fun Vector2D.dot(other: Vector2D): Double = x * other.x + y * other.y
}

View File

@ -2,6 +2,7 @@ package space.kscience.kmath.geometry
import space.kscience.kmath.linear.Point
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.SpaceElement
import space.kscience.kmath.operations.invoke
import kotlin.math.sqrt
@ -32,21 +33,22 @@ public val Vector3D.r: Double get() = Euclidean3DSpace { sqrt(norm()) }
private data class Vector3DImpl(
override val x: Double,
override val y: Double,
override val z: Double
override val z: Double,
) : Vector3D
public object Euclidean3DSpace : GeometrySpace<Vector3D> {
public object Euclidean3DSpace : GeometrySpace<Vector3D>, ScaleOperations<Vector3D> {
public override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) }
public fun Vector3D.norm(): Double = sqrt(x * x + y * y + z * z)
override fun Vector3D.unaryMinus(): Vector3D = Vector3D(-x, -y, -z)
public override fun Vector3D.distanceTo(other: Vector3D): Double = (this - other).norm()
public override fun add(a: Vector3D, b: Vector3D): Vector3D =
Vector3D(a.x + b.x, a.y + b.y, a.z + b.z)
public override fun multiply(a: Vector3D, k: Number): Vector3D =
Vector3D(a.x * k.toDouble(), a.y * k.toDouble(), a.z * k.toDouble())
public override fun scale(a: Vector3D, value: Double): Vector3D =
Vector3D(a.x * value, a.y * value, a.z * value)
public override fun Vector3D.dot(other: Vector3D): Double =
x * other.x + y * other.y + z * other.z

View File

@ -3,9 +3,10 @@ package space.kscience.kmath.histogram
import space.kscience.kmath.domains.Domain
import space.kscience.kmath.linear.Point
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.NDSpace
import space.kscience.kmath.nd.NDField
import space.kscience.kmath.nd.NDStructure
import space.kscience.kmath.nd.Strides
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.Space
import space.kscience.kmath.operations.SpaceElement
import space.kscience.kmath.operations.invoke
@ -41,10 +42,11 @@ public class IndexedHistogram<T : Comparable<T>, V : Any>(
/**
* A space for producing histograms with values in a NDStructure
*/
public interface IndexedHistogramSpace<T : Comparable<T>, V : Any> : Space<IndexedHistogram<T, V>> {
public interface IndexedHistogramSpace<T : Comparable<T>, V : Any>
: Space<IndexedHistogram<T, V>>, ScaleOperations<IndexedHistogram<T, V>> {
//public val valueSpace: Space<V>
public val strides: Strides
public val histogramValueSpace: NDSpace<V, *> //= NDAlgebra.space(valueSpace, Buffer.Companion::boxing, *shape),
public val histogramValueSpace: NDField<V, *> //= NDAlgebra.space(valueSpace, Buffer.Companion::boxing, *shape),
/**
* Resolve index of the bin including given [point]
@ -63,12 +65,12 @@ public interface IndexedHistogramSpace<T : Comparable<T>, V : Any> : Space<Index
override fun add(a: IndexedHistogram<T, V>, b: IndexedHistogram<T, V>): IndexedHistogram<T, V> {
require(a.context == this) { "Can't operate on a histogram produced by external space" }
require(b.context == this) { "Can't operate on a histogram produced by external space" }
return IndexedHistogram(this, histogramValueSpace.invoke { a.values + b.values })
return IndexedHistogram(this, histogramValueSpace { a.values + b.values })
}
override fun multiply(a: IndexedHistogram<T, V>, k: Number): IndexedHistogram<T, V> {
override fun scale(a: IndexedHistogram<T, V>, value: Double): IndexedHistogram<T, V> {
require(a.context == this) { "Can't operate on a histogram produced by external space" }
return IndexedHistogram(this, histogramValueSpace.invoke { a.values * k })
return IndexedHistogram(this, histogramValueSpace { a.values * value })
}
override val zero: IndexedHistogram<T, V> get() = produce { }

View File

@ -2,6 +2,7 @@ package space.kscience.kmath.histogram
import space.kscience.kmath.domains.Domain
import space.kscience.kmath.domains.HyperSquareDomain
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.*
import space.kscience.kmath.structures.*
import kotlin.math.floor
@ -40,6 +41,7 @@ public class RealHistogramSpace(
getIndex(it, point[it])
}
@OptIn(UnstableKMathAPI::class)
override fun getDomain(index: IntArray): Domain<Double> {
val lowerBoundary = index.mapIndexed { axis, i ->
when (i) {
@ -77,6 +79,8 @@ public class RealHistogramSpace(
return IndexedHistogram(this, values)
}
override fun IndexedHistogram<Double, Double>.unaryMinus(): IndexedHistogram<Double, Double> = this * (-1)
public companion object {
/**
* Use it like

View File

@ -2,6 +2,7 @@ package space.kscience.kmath.histogram
import space.kscience.kmath.domains.UnivariateDomain
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.Space
import space.kscience.kmath.structures.Buffer
import java.util.*
@ -36,7 +37,7 @@ public class TreeHistogram(
@UnstableKMathAPI
public class TreeHistogramSpace(
public val binFactory: (Double) -> UnivariateDomain,
) : Space<UnivariateHistogram> {
) : Space<UnivariateHistogram>, ScaleOperations<UnivariateHistogram> {
private class BinCounter(val domain: UnivariateDomain, val counter: Counter<Double> = Counter.real()) :
ClosedFloatingPointRange<Double> by domain.range
@ -97,14 +98,14 @@ public class TreeHistogramSpace(
return TreeHistogram(this, bins)
}
override fun multiply(a: UnivariateHistogram, k: Number): UnivariateHistogram {
override fun scale(a: UnivariateHistogram, value: Double): UnivariateHistogram {
val bins = TreeMap<Double, UnivariateBin>().apply {
a.bins.forEach { bin ->
put(bin.domain.center,
UnivariateBin(
bin.domain,
value = bin.value * k.toDouble(),
standardDeviation = abs(bin.standardDeviation * k.toDouble())
value = bin.value * value.toDouble(),
standardDeviation = abs(bin.standardDeviation * value.toDouble())
)
)
}
@ -113,6 +114,8 @@ public class TreeHistogramSpace(
return TreeHistogram(this, bins)
}
override fun UnivariateHistogram.unaryMinus(): UnivariateHistogram = this * (-1)
override val zero: UnivariateHistogram = produce { }
public companion object {

View File

@ -8,6 +8,7 @@ import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.asSequence
@UnstableKMathAPI
public val UnivariateDomain.center: Double get() = (range.endInclusive - range.start) / 2
/**
@ -15,6 +16,7 @@ public val UnivariateDomain.center: Double get() = (range.endInclusive - range.s
* @param value The value of histogram including weighting
* @param standardDeviation Standard deviation of the bin value. Zero or negative if not applicable
*/
@UnstableKMathAPI
public class UnivariateBin(
public val domain: UnivariateDomain,
override val value: Double,

View File

@ -20,7 +20,7 @@ internal fun NDAlgebra<*, *>.checkShape(array: INDArray): INDArray {
* @param T the type of ND-structure element.
* @param C the type of the element context.
*/
public interface Nd4jArrayAlgebra<T, C> : NDAlgebra<T, C> {
public interface Nd4jArrayAlgebra<T, C : Algebra<T>> : NDAlgebra<T, C> {
/**
* Wraps [INDArray] to [N].
*/
@ -92,18 +92,9 @@ public interface Nd4jArraySpace<T, S : Space<T>> : NDSpace<T, S>, Nd4jArrayAlgeb
return ndArray.neg().wrap()
}
public override fun multiply(a: NDStructure<T>, k: Number): Nd4jArrayStructure<T> {
public fun multiply(a: NDStructure<T>, k: Number): Nd4jArrayStructure<T> {
return a.ndArray.mul(k).wrap()
}
@Deprecated("Avoid using this method, underlying array get casted to Doubles")
public override operator fun NDStructure<T>.div(k: Number): Nd4jArrayStructure<T> {
return ndArray.div(k).wrap()
}
public override operator fun NDStructure<T>.times(k: Number): Nd4jArrayStructure<T> {
return ndArray.mul(k).wrap()
}
}
/**
@ -180,8 +171,7 @@ public interface Nd4jArrayField<T, F : Field<T>> : NDField<T, F>, Nd4jArrayRing<
public override fun divide(a: NDStructure<T>, b: NDStructure<T>): Nd4jArrayStructure<T> =
a.ndArray.div(b.ndArray).wrap()
public override operator fun Number.div(b: NDStructure<T>): Nd4jArrayStructure<T> = b.ndArray.rdiv(this).wrap()
public operator fun Number.div(b: NDStructure<T>): Nd4jArrayStructure<T> = b.ndArray.rdiv(this).wrap()
public companion object {
private val floatNd4jArrayFieldCache: ThreadLocal<MutableMap<IntArray, FloatNd4jArrayField>> =
@ -218,11 +208,14 @@ public interface Nd4jArrayField<T, F : Field<T>> : NDField<T, F>, Nd4jArrayRing<
* Represents [NDField] over [Nd4jArrayRealStructure].
*/
public class RealNd4jArrayField(public override val shape: IntArray) : Nd4jArrayField<Double, RealField> {
public override val elementContext: RealField
get() = RealField
public override val elementContext: RealField get() = RealField
public override fun INDArray.wrap(): Nd4jArrayStructure<Double> = checkShape(this).asRealStructure()
override fun scale(a: NDStructure<Double>, value: Double): Nd4jArrayStructure<Double> {
return a.ndArray.mul(value).wrap()
}
public override operator fun NDStructure<Double>.div(arg: Double): Nd4jArrayStructure<Double> {
return ndArray.div(arg).wrap()
}
@ -257,6 +250,10 @@ public class FloatNd4jArrayField(public override val shape: IntArray) : Nd4jArra
public override fun INDArray.wrap(): Nd4jArrayStructure<Float> = checkShape(this).asFloatStructure()
override fun scale(a: NDStructure<Float>, value: Double): NDStructure<Float> {
return a.ndArray.mul(value).wrap()
}
public override operator fun NDStructure<Float>.div(arg: Float): Nd4jArrayStructure<Float> {
return ndArray.div(arg).wrap()
}

View File

@ -4,6 +4,7 @@ import space.kscience.kmath.chains.Chain
import space.kscience.kmath.chains.ConstantChain
import space.kscience.kmath.chains.map
import space.kscience.kmath.chains.zip
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.Space
import space.kscience.kmath.operations.invoke
@ -18,14 +19,18 @@ public class ConstantSampler<T : Any>(public val value: T) : Sampler<T> {
/**
* A space for samplers. Allows to perform simple operations on distributions
*/
public class SamplerSpace<T : Any>(public val space: Space<T>) : Space<Sampler<T>> {
public override val zero: Sampler<T> = ConstantSampler(space.zero)
public class SamplerSpace<T : Any, S>(public val algebra: S) : Space<Sampler<T>>,
ScaleOperations<Sampler<T>> where S : Space<T>, S : ScaleOperations<T> {
public override val zero: Sampler<T> = ConstantSampler(algebra.zero)
public override fun add(a: Sampler<T>, b: Sampler<T>): Sampler<T> = BasicSampler { generator ->
a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> space { aValue + bValue } }
a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> algebra { aValue + bValue } }
}
public override fun multiply(a: Sampler<T>, k: Number): Sampler<T> = BasicSampler { generator ->
a.sample(generator).map { space { it * k.toDouble() } }
public override fun scale(a: Sampler<T>, value: Double): Sampler<T> = BasicSampler { generator ->
a.sample(generator).map { algebra { it * value } }
}
override fun Sampler<T>.unaryMinus(): Sampler<T> = scale(this, -1.0)
}

View File

@ -43,7 +43,7 @@ public interface ComposableStatistic<T, I, R> : Statistic<T, R> {
@ExperimentalCoroutinesApi
private fun <T, I, R> ComposableStatistic<T, I, R>.flowIntermediate(
flow: Flow<Buffer<T>>,
dispatcher: CoroutineDispatcher = Dispatchers.Default
dispatcher: CoroutineDispatcher = Dispatchers.Default,
): Flow<I> = flow
.mapParallel(dispatcher) { computeIntermediate(it) }
.runningReduce(::composeIntermediate)
@ -59,27 +59,31 @@ private fun <T, I, R> ComposableStatistic<T, I, R>.flowIntermediate(
@ExperimentalCoroutinesApi
public fun <T, I, R> ComposableStatistic<T, I, R>.flow(
flow: Flow<Buffer<T>>,
dispatcher: CoroutineDispatcher = Dispatchers.Default
dispatcher: CoroutineDispatcher = Dispatchers.Default,
): Flow<R> = flowIntermediate(flow, dispatcher).map(::toResult)
/**
* Arithmetic mean
*/
public class Mean<T>(public val space: Space<T>) : ComposableStatistic<T, Pair<T, Int>, T> {
public class Mean<T>(
private val space: Space<T>,
private val division: (sum: T, count: Int) -> T,
) : ComposableStatistic<T, Pair<T, Int>, T> {
public override suspend fun computeIntermediate(data: Buffer<T>): Pair<T, Int> =
space { sum(data.asIterable()) } to data.size
public override suspend fun composeIntermediate(first: Pair<T, Int>, second: Pair<T, Int>): Pair<T, Int> =
space { first.first + second.first } to (first.second + second.second)
public override suspend fun toResult(intermediate: Pair<T, Int>): T =
space { intermediate.first / intermediate.second }
public override suspend fun toResult(intermediate: Pair<T, Int>): T = space {
division(intermediate.first, intermediate.second)
}
public companion object {
//TODO replace with optimized version which respects overflow
public val real: Mean<Double> = Mean(RealField)
public val int: Mean<Int> = Mean(IntRing)
public val long: Mean<Long> = Mean(LongRing)
public val real: Mean<Double> = Mean(RealField) { sum, count -> sum / count }
public val int: Mean<Int> = Mean(IntRing) { sum, count -> sum / count }
public val long: Mean<Long> = Mean(LongRing) { sum, count -> sum / count }
}
}

View File

@ -26,7 +26,7 @@ public final class space/kscience/kmath/viktor/ViktorBuffer : space/kscience/kma
public final synthetic fun unbox-impl ()Lorg/jetbrains/bio/viktor/F64FlatArray;
}
public final class space/kscience/kmath/viktor/ViktorNDField : space/kscience/kmath/nd/NDField, space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/RingWithNumbers {
public final class space/kscience/kmath/viktor/ViktorNDField : space/kscience/kmath/nd/NDField, space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/ScaleOperations {
public fun <init> ([I)V
public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object;
public fun acos-Q7Xurp0 (Lspace/kscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
@ -55,8 +55,6 @@ public final class space/kscience/kmath/viktor/ViktorNDField : space/kscience/km
public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object;
public fun cosh (Lspace/kscience/kmath/nd/NDStructure;)Lspace/kscience/kmath/nd/NDStructure;
public fun div (DLspace/kscience/kmath/nd/NDStructure;)Lspace/kscience/kmath/nd/NDStructure;
public synthetic fun div (Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object;
public fun div (Ljava/lang/Number;Lspace/kscience/kmath/nd/NDStructure;)Lspace/kscience/kmath/nd/NDStructure;
public synthetic fun div (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public synthetic fun div (Ljava/lang/Object;Lspace/kscience/kmath/nd/NDStructure;)Lspace/kscience/kmath/nd/NDStructure;
@ -68,7 +66,7 @@ public final class space/kscience/kmath/viktor/ViktorNDField : space/kscience/km
public fun divide (Lspace/kscience/kmath/nd/NDStructure;Lspace/kscience/kmath/nd/NDStructure;)Lspace/kscience/kmath/nd/NDStructure;
public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object;
public fun exp-Q7Xurp0 (Lspace/kscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
public synthetic fun getElementContext ()Ljava/lang/Object;
public synthetic fun getElementContext ()Lspace/kscience/kmath/operations/Algebra;
public fun getElementContext ()Lspace/kscience/kmath/operations/RealField;
public final fun getF64Buffer (Lspace/kscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
public synthetic fun getOne ()Ljava/lang/Object;
@ -96,11 +94,8 @@ public final class space/kscience/kmath/viktor/ViktorNDField : space/kscience/km
public fun minus (Lspace/kscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lspace/kscience/kmath/nd/NDStructure;
public synthetic fun minus (Lspace/kscience/kmath/nd/NDStructure;Ljava/lang/Object;)Lspace/kscience/kmath/nd/NDStructure;
public fun minus-s8yP2C4 (Lspace/kscience/kmath/nd/NDStructure;Lspace/kscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public synthetic fun multiply (Lspace/kscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lspace/kscience/kmath/nd/NDStructure;
public fun multiply (Lspace/kscience/kmath/nd/NDStructure;Lspace/kscience/kmath/nd/NDStructure;)Lspace/kscience/kmath/nd/NDStructure;
public fun multiply-s8yP2C4 (Lspace/kscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lorg/jetbrains/bio/viktor/F64Array;
public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object;
public fun number-Q7Xurp0 (Ljava/lang/Number;)Lorg/jetbrains/bio/viktor/F64Array;
public fun plus (DLspace/kscience/kmath/nd/NDStructure;)Lspace/kscience/kmath/nd/NDStructure;
@ -122,6 +117,8 @@ public final class space/kscience/kmath/viktor/ViktorNDField : space/kscience/km
public synthetic fun rightSideNumberOperation (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object;
public fun rightSideNumberOperation (Ljava/lang/String;Lspace/kscience/kmath/nd/NDStructure;Ljava/lang/Number;)Lspace/kscience/kmath/nd/NDStructure;
public fun rightSideNumberOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2;
public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object;
public fun scale-s8yP2C4 (Lspace/kscience/kmath/nd/NDStructure;D)Lorg/jetbrains/bio/viktor/F64Array;
public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object;
public fun sin-Q7Xurp0 (Lspace/kscience/kmath/nd/NDStructure;)Lorg/jetbrains/bio/viktor/F64Array;
public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object;

View File

@ -4,8 +4,9 @@ import org.jetbrains.bio.viktor.F64Array
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.NumbersAddOperations
import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.RingWithNumbers
import space.kscience.kmath.operations.ScaleOperations
@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public inline class ViktorNDStructure(public val f64Buffer: F64Array) : MutableNDStructure<Double> {
@ -26,7 +27,8 @@ public fun F64Array.asStructure(): ViktorNDStructure = ViktorNDStructure(this)
@OptIn(UnstableKMathAPI::class)
@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public class ViktorNDField(public override val shape: IntArray) : NDField<Double, RealField>,
RingWithNumbers<NDStructure<Double>>, ExtendedField<NDStructure<Double>> {
NumbersAddOperations<NDStructure<Double>>, ExtendedField<NDStructure<Double>>,
ScaleOperations<NDStructure<Double>> {
public val NDStructure<Double>.f64Buffer: F64Array
get() = when {
@ -55,6 +57,8 @@ public class ViktorNDField(public override val shape: IntArray) : NDField<Double
}
}.asStructure()
override fun NDStructure<Double>.unaryMinus(): NDStructure<Double> = this * (-1)
public override fun NDStructure<Double>.map(transform: RealField.(Double) -> Double): ViktorNDStructure =
F64Array(*this@ViktorNDField.shape).apply {
this@ViktorNDField.strides.indices().forEach { index ->
@ -83,8 +87,8 @@ public class ViktorNDField(public override val shape: IntArray) : NDField<Double
public override fun add(a: NDStructure<Double>, b: NDStructure<Double>): ViktorNDStructure =
(a.f64Buffer + b.f64Buffer).asStructure()
public override fun multiply(a: NDStructure<Double>, k: Number): ViktorNDStructure =
(a.f64Buffer * k.toDouble()).asStructure()
public override fun scale(a: NDStructure<Double>, value: Double): ViktorNDStructure =
(a.f64Buffer * value.toDouble()).asStructure()
public override inline fun NDStructure<Double>.plus(b: NDStructure<Double>): ViktorNDStructure =
(f64Buffer + b.f64Buffer).asStructure()

View File

@ -1,14 +1,15 @@
pluginManagement {
repositories {
maven("https://repo.kotlin.link")
mavenLocal()
gradlePluginPortal()
jcenter()
maven("https://repo.kotlin.link")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/kotlin/kotlinx")
}
val toolsVersion = "0.8.1"
val kotlinVersion = "1.4.30"
val toolsVersion = "0.9.1"
val kotlinVersion = "1.4.31"
plugins {
id("kotlinx.benchmark") version "0.2.0-dev-20"