diff --git a/CHANGELOG.md b/CHANGELOG.md index a19b1f467..848920fbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Complex power - Separate methods for UInt, Int and Number powers. NaN safety. - Tensorflow prototype +- OjAlgo support ### Changed - Exponential operations merged with hyperbolic functions diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index 96c17a215..e878edbbf 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -17,4 +17,4 @@ dependencies { readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL -} \ No newline at end of file +} diff --git a/kmath-ojalgo/build.gradle.kts b/kmath-ojalgo/build.gradle.kts new file mode 100644 index 000000000..d7166f441 --- /dev/null +++ b/kmath-ojalgo/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + kotlin("jvm") + id("ru.mipt.npm.gradle.common") +} + +dependencies { + api("org.ojalgo:ojalgo:48.4.1") + api(project(":kmath-complex")) +} + +readme { + description = "OjAlgo bindings" + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) +} diff --git a/kmath-ojalgo/src/main/kotlin/space/kscience/kmath/ojalgo/OjalgoAlgebra.kt b/kmath-ojalgo/src/main/kotlin/space/kscience/kmath/ojalgo/OjalgoAlgebra.kt new file mode 100644 index 000000000..e19cf2aaa --- /dev/null +++ b/kmath-ojalgo/src/main/kotlin/space/kscience/kmath/ojalgo/OjalgoAlgebra.kt @@ -0,0 +1,42 @@ +package space.kscience.kmath.ojalgo + +import org.ojalgo.algebra.ScalarOperation +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.Group +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke + +public open class OjalgoGroup(override val zero: T) : Group + where T : org.ojalgo.algebra.Group.Additive { + public override fun add(a: T, b: T): T = a.add(b) + public override fun T.unaryMinus(): T = negate() +} + +public open class OjalgoRing(zero: T, override val one: T) : OjalgoGroup(zero), + Ring where T : org.ojalgo.algebra.Ring { + public override fun multiply(a: T, b: T): T = a.multiply(b) +} + +public open class OjalgoField(zero: T, one: T) : OjalgoRing(zero, one), + Field where T : org.ojalgo.algebra.Field, T : ScalarOperation.Multiplication { + public override fun divide(a: T, b: T): T = a.divide(b) + public override fun scale(a: T, value: Double): T = a.multiply(value) +} + +internal inline fun Field.convert(crossinline tToR: (T) -> R, crossinline rToT: (R) -> T): Field = + object : Field { + override val zero: R + get() = tToR(this@convert.zero) + + override val one: R + get() = tToR(this@convert.one) + + override fun add(a: R, b: R): R = tToR(this@convert.add(rToT(a), rToT(b))) + override fun multiply(a: R, b: R): R = tToR(this@convert.multiply(rToT(a), rToT(b))) + override fun divide(a: R, b: R): R = tToR(this@convert.divide(rToT(a), rToT(b))) + override fun R.unaryMinus(): R = tToR(this@convert { -rToT(this@unaryMinus) }) + + override fun scale(a: R, value: Double): R { + return tToR(this@convert.scale(rToT(a), value)) + } + } diff --git a/kmath-ojalgo/src/main/kotlin/space/kscience/kmath/ojalgo/OjalgoMatrices.kt b/kmath-ojalgo/src/main/kotlin/space/kscience/kmath/ojalgo/OjalgoMatrices.kt new file mode 100644 index 000000000..1d3a8b909 --- /dev/null +++ b/kmath-ojalgo/src/main/kotlin/space/kscience/kmath/ojalgo/OjalgoMatrices.kt @@ -0,0 +1,34 @@ +package space.kscience.kmath.ojalgo + +import org.ojalgo.structure.Access1D +import org.ojalgo.structure.Access2D +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.linear.Point + +public class OjalgoMatrix>(public val origin: Access2D) : Matrix { + public override val rowNum: Int + get() = Math.toIntExact(origin.countRows()) + + public override val colNum: Int + get() = Math.toIntExact(origin.countColumns()) + + public override fun get(i: Int, j: Int): T = origin[i.toLong(), j.toLong()] +} + +public class OjalgoVector>(public val origin: Access1D) : Point { + public override val size: Int + get() = origin.size() + + override fun get(index: Int): T = origin[index.toLong()] + + public override operator fun iterator(): Iterator = object : Iterator { + private var cursor: Int = 0 + + override fun next(): T { + cursor += 1 + return this@OjalgoVector[cursor - 1] + } + + override fun hasNext(): Boolean = cursor < size + } +} diff --git a/kmath-ojalgo/src/main/kotlin/space/kscience/kmath/ojalgo/OjalgoScalars.kt b/kmath-ojalgo/src/main/kotlin/space/kscience/kmath/ojalgo/OjalgoScalars.kt new file mode 100644 index 000000000..ac8fd9bd1 --- /dev/null +++ b/kmath-ojalgo/src/main/kotlin/space/kscience/kmath/ojalgo/OjalgoScalars.kt @@ -0,0 +1,31 @@ +package space.kscience.kmath.ojalgo + +import org.ojalgo.scalar.* +import space.kscience.kmath.complex.Complex +import space.kscience.kmath.operations.Field + +public val OjalgoMoneyField: Field> = OjalgoField>(Money.ZERO, Money.ONE) + +public val OjalgoComplexField: Field = + OjalgoField>(ComplexNumber.ZERO, ComplexNumber.ONE).convert( + { Complex(it.get().real, it.get().imaginary) }, + { ComplexNumber.of(it.re, it.im) }, + ) + +public val OjalgoRationalField: Field = + OjalgoField>(RationalNumber.ZERO, RationalNumber.ONE).convert( + Scalar::doubleValue, + RationalNumber::valueOf, + ) + +public val OjalgoQuaternionField: Field = + OjalgoField>(Quaternion.ZERO, Quaternion.ONE).convert( + { x -> space.kscience.kmath.complex.Quaternion(x.get().scalar(), x.get().i, x.get().j, x.get().k) }, + { (s, i, j, k) -> Quaternion.of(s, i, j, k) }, + ) + +public val OjalgoPrimitiveField: Field = + OjalgoField>(PrimitiveScalar.ZERO, PrimitiveScalar.ONE).convert( + Scalar::doubleValue, + PrimitiveScalar::valueOf, + ) diff --git a/settings.gradle.kts b/settings.gradle.kts index b3c275810..905bb2b93 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,5 +26,6 @@ include( ":kmath-symja", ":kmath-jafama", ":examples", + ":kmath-ojalgo", ":benchmarks", )