From 1b712e6dd3ed9be02f50f8c91f96bfc06b8642bb Mon Sep 17 00:00:00 2001 From: breandan Date: Wed, 8 Dec 2021 01:42:59 -0500 Subject: [PATCH] finish KMP migraiton, fixes breandan/kotlingrad#24 --- core/build.gradle.kts | 3 +- .../ai/hypergraph/kotlingrad/CommonUtils.kt | 4 +- .../ai/hypergraph/kotlingrad/api/Bindings.kt | 10 +- .../ai/hypergraph/kotlingrad/api/Matrix.kt | 3 +- .../ai/hypergraph/kotlingrad/api/Scalar.kt | 470 +++++++++++++++++ .../ai/hypergraph/kotlingrad/api/Vector.kt | 5 +- .../ai/hypergraph/kotlingrad/shapes/Shapes.kt | 0 .../kotlingrad/typelevel/VariableCapture.kt | 0 .../kotlingrad/typelevel/Variables.kt | 16 +- .../ai/hypergraph/kotlingrad/api/Scalar.kt | 471 ------------------ .../ai/hypergraph/kotlingrad/api/Utils.kt | 4 +- .../kotlingrad/notebook/KotlinJupyter.kt | 2 +- kaliningraph | 2 +- .../ai/hypergraph/shipshape/Shipshape.kt | 2 +- .../kotlin/ai/hypergraph/shipshape/VarGen.kt | 4 +- 15 files changed, 498 insertions(+), 498 deletions(-) rename core/src/{jvmMain => commonMain}/kotlin/ai/hypergraph/kotlingrad/api/Bindings.kt (92%) rename core/src/{jvmMain => commonMain}/kotlin/ai/hypergraph/kotlingrad/api/Matrix.kt (99%) rename core/src/{jvmMain => commonMain}/kotlin/ai/hypergraph/kotlingrad/api/Vector.kt (99%) rename core/src/{jvmMain => commonMain}/kotlin/ai/hypergraph/kotlingrad/shapes/Shapes.kt (100%) rename core/src/{jvmMain => commonMain}/kotlin/ai/hypergraph/kotlingrad/typelevel/VariableCapture.kt (100%) rename core/src/{jvmMain => commonMain}/kotlin/ai/hypergraph/kotlingrad/typelevel/Variables.kt (97%) delete mode 100644 core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Scalar.kt diff --git a/core/build.gradle.kts b/core/build.gradle.kts index f5d8abd5..3d271fa9 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -115,6 +115,7 @@ kotlin { dependencies { implementation(kotlin("stdlib-common")) implementation(kotlin("reflect")) + api("ai.hypergraph:kaliningraph:0.1.9") } } @@ -123,8 +124,6 @@ kotlin { implementation(kotlin("bom")) implementation(kotlin("stdlib")) - api("ai.hypergraph:kaliningraph:0.1.9") - implementation("org.graalvm.js:js:21.3.0") implementation("guru.nidi:graphviz-kotlin:0.18.1") diff --git a/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/CommonUtils.kt b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/CommonUtils.kt index 22c868f5..9b0feeb2 100644 --- a/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/CommonUtils.kt +++ b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/CommonUtils.kt @@ -52,4 +52,6 @@ fun String.superscript() = }.joinToString("").replace(" ", "") fun Iterable.repeat(n: Int) = - sequence { repeat(n) { yieldAll(this@repeat) } } \ No newline at end of file + sequence { repeat(n) { yieldAll(this@repeat) } } + +var EAGER = false diff --git a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Bindings.kt b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Bindings.kt similarity index 92% rename from core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Bindings.kt rename to core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Bindings.kt index eb64dcda..6f17ec35 100644 --- a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Bindings.kt +++ b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Bindings.kt @@ -68,10 +68,10 @@ data class Bindings> constructor(val fMap: MapFxF) { operator fun minus(func: Fun) = Bindings(fMap.filterNot { it.key == func }) // Scalar, vector, and matrix variables - val sVars: Set> = sVarMap.keys.toSortedSet { v1, v2 -> v1.name.compareTo(v2.name) } - val vVars: Set> = vVarMap.keys.toSortedSet { v1, v2 -> v1.name.compareTo(v2.name) } - val mVars: Set> = mVarMap.keys.toSortedSet { v1, v2 -> v1.name.compareTo(v2.name) } - val allVars: Set> = sVars + vVars + mVars + val sVars: List> = sVarMap.keys.sortedBy { it.name } + val vVars: List> = vVarMap.keys.sortedBy { it.name } + val mVars: List> = mVarMap.keys.sortedBy { it.name } + val allVars: List> = sVars + vVars + mVars val allFreeVariables by lazy { allVarMap.filterValues { containsFreeVariable(it) } } val allBoundVariables: Map, Fun> by lazy { allVarMap.filterValues { !containsFreeVariable(it) } } @@ -95,7 +95,7 @@ data class Bindings> constructor(val fMap: MapFxF) { val boundVars = allBoundVariables.keys val unpropagated = (freeVars intersect boundVars).map { it to this[it] } require(unpropagated.isEmpty()) { - before.show("input"); after.show("result") + //before.show("input"); after.show("result") "Free vars: $freeVars\n" + "Bindings were $this\n" + "Result included unpropagated variables: $unpropagated" diff --git a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Matrix.kt b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Matrix.kt similarity index 99% rename from core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Matrix.kt rename to core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Matrix.kt index a8d8687b..5c71055b 100644 --- a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Matrix.kt +++ b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Matrix.kt @@ -6,6 +6,7 @@ import ai.hypergraph.kaliningraph.circuits.Op import ai.hypergraph.kaliningraph.circuits.Ops import ai.hypergraph.kaliningraph.tensor.DoubleMatrix import ai.hypergraph.kaliningraph.* +import ai.hypergraph.kotlingrad.EAGER import ai.hypergraph.kotlingrad.api.VFun.Companion.KG_IT import ai.hypergraph.kotlingrad.shapes.D1 import ai.hypergraph.kotlingrad.shapes.DN @@ -30,7 +31,7 @@ open class MFun(override vararg val inputs: Fun): Fun try { it as Mat } catch (e: ClassCastException) { - show("before"); it.show("after") + //show("before"); it.show("after") throw NumberFormatException("Matrix function has unbound free variables: ${bindings.allFreeVariables.keys}") } } diff --git a/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Scalar.kt b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Scalar.kt index cdf2780e..debe70f2 100644 --- a/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Scalar.kt +++ b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Scalar.kt @@ -1,5 +1,475 @@ +@file:Suppress("FunctionName", "LocalVariableName", "unused", "UNUSED_VARIABLE") package ai.hypergraph.kotlingrad.api +import ai.hypergraph.kaliningraph.circuits.* +import ai.hypergraph.kotlingrad.EAGER +import ai.hypergraph.kotlingrad.shapes.* +import kotlin.Double.Companion.NaN +import kotlin.math.* +import kotlin.reflect.KProperty + +/** + * Interface representing a generic mathematical function. + * + * TODO: Implement proper monad like [java.util.function.Function] or [Function] + */ + +interface Fun>: (Bindings) -> Fun { + val inputs: Array> + val bindings: Bindings + get() = Bindings(*inputs) + val op: Op + + fun isConstant(): Boolean = bindings.allVars.isEmpty() + fun wrap(number: Number): SConst = SConst(number.toDouble()) + + override operator fun invoke(newBindings: Bindings): Fun + operator fun invoke(): Fun + operator fun invoke(vararg numbers: Number): Fun = + invoke(bindings.zip(numbers.map { wrap(it) })) + + operator fun invoke(vararg funs: Fun): Fun = invoke(bindings.zip(funs.toList())) + + operator fun invoke(vararg ps: FunToAny): Fun = invoke(ps.toList().bind()) + + fun toGate(): Gate = when (this) { + is NilFun -> Gate.wrap(this) + is UnFun -> Gate(op, input.toGate()) + is BiFun -> Gate(op, left.toGate(), right.toGate()) + is PolyFun -> Gate(op, *inputs.map { it.toGate() }.toTypedArray()) + else -> TODO(this::class.simpleName!!) + } + + fun toGraph() = toGate().graph + + fun List>.bind() = Bindings(associate { it.first to wrapOrError(it.second) }) + + fun wrapOrError(any: Any): Fun = when (any) { + is Fun<*> -> any as Fun + is Number -> wrap(any) + is List<*> -> when { + any.isEmpty() -> throw Exception("Empty collection") + any.first() is Number -> Vec(any.map { wrap(it as Number) }) + else -> TODO() // else if(any.first() is List<*>) Mat() + } + is Array<*> -> wrapOrError(any.toList()) + else -> throw NumberFormatException("Invoke expects a number or function but got: $any") + } + + fun asString(): String = when (this) { + is Constant -> "$this" + is Variable -> "Var($name)" + is Grad -> "d($input) / d($vrb)" + is SComposition -> "($input)$bindings" + is Power<*> -> "($left).$op($right)" //TODO: separate asString() and toCode() + is BiFun<*> -> "($left) $op ($right)" + is UnFun<*> -> "$op($input)" + is PolyFun<*> -> "$op$inputs" + else -> this::class.simpleName!! + } +} + +// https://arxiv.org/pdf/2001.02209.pdf + +// Describes the arity of the operator + +interface NilFun>: Fun + +interface UnFun>: PolyFun { + val input: Fun +} + +interface BiFun>: PolyFun { + val left: Fun + val right: Fun +} + +interface PolyFun>: Fun { + override val inputs: Array> +} + +interface Grad>: BiFun { + val input: Fun + val vrb: Variable + override val left: Fun + get() = input + override val right: Fun + get() = vrb +} + +interface Variable>: Fun, NilFun { + val name: String +} + +interface Constant>: Fun, NilFun + +/** + * Scalar function. + */ + +sealed class SFun> +constructor(override vararg val inputs: Fun): PolyFun, Field> { + val ZERO: Special by lazy { Zero() } + val ONE: Special by lazy { One() } + val TWO: Special by lazy { Two() } + val E: Special by lazy { E() } + + override fun plus(addend: SFun): SFun = Sum(this, addend) + override fun times(multiplicand: SFun): SFun = Prod(this, multiplicand) + override fun div(divisor: SFun): SFun = this * divisor.pow(-ONE) + open operator fun times(multiplicand: VFun): VFun = SVProd(this, multiplicand) + open operator fun times(multiplicand: MFun): MFun = SMProd(this, multiplicand) + + /** + * TODO: Parameterize operator in constructor instead of using subtyping, + * this would allow us to migrate from subclass to operator matching [Gate]. + */ + + class AOP>(val op: Op, val of: (Fun) -> SFun) + + // TODO: Implement a proper curry and lower variadic apply onto it. + fun apply(op: Op): (SFun) -> SFun = when (op) { + Ops.sum -> { it: SFun -> this + it } + Ops.prod -> { it: SFun -> this * it } + else -> TODO(op::class.simpleName!!) + } + + /** + * TODO: Figure out how to avoid casting. Once stable, port to [VFun], [MFun]. + */ + + @Suppress("UNCHECKED_CAST") + fun apply(vararg xs: Fun): SFun = when (op) { + Ops.id -> this + Ops.sin -> (xs[0] as SFun).sin() + Ops.cos -> (xs[0] as SFun).cos() + Ops.tan -> (xs[0] as SFun).tan() + Ops.sub -> -(xs[0] as SFun) + + Ops.d -> TODO() + Ops.sum -> (xs[0] as SFun) + xs[1] as SFun + Ops.prod -> (xs[0] as SFun) * xs[1] as SFun + Ops.pow -> (xs[0] as SFun) pow xs[1] as SFun + Ops.log -> (xs[0] as SFun).log(xs[1] as SFun) + Ops.dot -> (xs[0] as VFun) dot xs[1] as VFun + + Ops.Σ -> (xs[0] as VFun).sum() + Ops.λ -> TODO() + else -> TODO(op::class.simpleName!!) + } + + override val op: Op = when (this) { + is SVar -> Ops.id + is SConst -> Ops.id + is Sine -> Ops.sin + is Cosine -> Ops.cos + is Tangent -> Ops.tan + is Negative -> Ops.sub + + is Sum -> Ops.sum + is Prod -> Ops.prod + is Power -> Ops.pow + is Log -> Ops.log + is Derivative -> Ops.d + is DProd -> Ops.dot + + is SComposition -> Ops.λ + is VSumAll -> Ops.Σ + } + + override fun invoke(newBindings: Bindings): SFun = + SComposition(this, newBindings).run { + if (bindings.complete || newBindings.readyToBind || EAGER) evaluate else this + } + + override operator fun invoke(): SFun = SComposition(this).evaluate + override operator fun invoke(vararg numbers: Number): SFun = + invoke(bindings.zip(numbers.map { wrap(it) })) + + override operator fun invoke(vararg funs: Fun): SFun = + invoke(bindings.zip(funs.toList())) + + override operator fun invoke(vararg ps: FunToAny): SFun = + invoke(ps.toList().bind()) + + open fun d(v1: SVar): SFun = + Derivative(this, v1)//.let { if (EAGER) it.df() else it } + + open fun sin(): SFun = Sine(this) + open fun cos(): SFun = Cosine(this) + open fun tan(): SFun = Tangent(this) + fun exp(): SFun = Power(E, this) + + open fun d(vVar: VVar): VFun = + Gradient(this, vVar)//.let { if(EAGER) it.df() else it } + + open fun d(mVar: MVar): MFun = + MGradient(this, mVar)//.let { if(EAGER) it.df() else it } + + open fun grad(): Map, SFun> = + bindings.sVars.associateWith { Derivative(this, it) } + + fun ln() = log(E) + override fun log(base: SFun): SFun = Log(this, base) + override fun pow(exponent: SFun): SFun = Power(this, exponent) + override fun unaryMinus(): SFun = Negative(this) + override fun unaryPlus(): SFun = this + open fun sqrt(): SFun = this pow (ONE / TWO) + + operator fun div(divisor: Number): SFun = this / wrap(divisor) + operator fun plus(addend: Number): SFun = this + wrap(addend) + operator fun minus(subtrahend: Number): SFun = this - wrap(subtrahend) + operator fun times(multiplicand: Number): SFun = this * wrap(multiplicand) + infix fun pow(exp: Number): SFun = this pow wrap(exp) + + override fun toString() = when (this) { + is SVar -> name + is SComposition -> "($input)$bindings" + else -> asString() + } + + // TODO: Implement symbolic dis/unification + override fun equals(other: Any?) = super.equals(other) +} + +/** + * Symbolic operators. + */ + +class Sine>(override val input: SFun): SFun(input), UnFun +class Cosine>(override val input: SFun): SFun(input), UnFun +class Tangent>(override val input: SFun): SFun(input), UnFun +class Negative>(override val input: SFun): SFun(input), UnFun +class Sum>(override val left: SFun, override val right: SFun): SFun(left, right), BiFun +class Prod>(override val left: SFun, override val right: SFun): SFun(left, right), BiFun +class Power>(override val left: SFun, override val right: SFun): SFun(left, right), BiFun +class Log>(override val left: SFun, override val right: SFun = E()): SFun(left, right), BiFun + +class Derivative> constructor( + override val input: SFun, + override val vrb: SVar +): SFun(input, vrb), Grad { + fun df() = input.df() + + @Suppress("UNCHECKED_CAST") + fun SFun.df(): SFun = when (this@df) { + is SVar -> if (this == vrb) ONE else ZERO + is SConst -> ZERO + is Sum -> left.df() + right.df() + is Prod -> left.df() * right + left * right.df() + is Power -> + //https://en.wikipedia.org/wiki/Differentiation_rules#The_polynomial_or_elementary_power_rule + if (right.isConstant()) right * left.pow(right - ONE) * left.df() + //https://en.wikipedia.org/wiki/Differentiation_rules#Generalized_power_rule + else this * (left.df() * right / left + right.df() * left.ln()) + is Negative -> -input.df() + is Log -> (left pow -ONE) * left.df() + is Sine -> input.cos() * input.df() + is Cosine -> -input.sin() * input.df() + is Tangent -> (input.cos() pow -TWO) * input.df() + is Derivative -> input.df().df() + is DProd -> (left.d(vrb) as VFun dot right as VFun) + (left as VFun dot right.d(vrb)) + is SComposition -> evaluate.df() + is VSumAll -> input.d(vrb).sum() +// is Custom -> fn.df() + } +} + +class SComposition> constructor( + override val input: SFun, + arguments: Bindings = Bindings(input) +): SFun(input), UnFun { + override val bindings: Bindings = input.bindings + arguments + val evaluate: SFun by lazy { bind(bindings) } + + // TODO: Look into deep recursion so that we don't blow the stack + // https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-deep-recursive-function + // https://medium.com/@elizarov/deep-recursion-with-coroutines-7c53e15993e3 + + fun SFun.bind(bnds: Bindings): SFun = + bnds[this@bind] ?: when (this@bind) { + is Derivative -> df().bind(bnds) + // TODO: should we really be merging bindings for nested composition? + is SComposition -> input.bind(bnds + bindings) + else -> apply(*inputs.map { + if (it is SFun) it.bind(bnds) else it(bnds) + }.toTypedArray()) + } //.also { result -> bnds.checkForUnpropagatedVariables(this@bind, result) } + //appl(*inputs.map { it.bind(bnds) }.toTypedArray())) as SFun +} + +class DProd> constructor( + override val left: VFun, + override val right: VFun +): SFun(left, right), BiFun + +class VSumAll, E: D1> +constructor(val input: VFun): SFun(input), PolyFun { + override val inputs: Array> = arrayOf(input) +} + +class SVar>(override val name: String = ""): Variable, SFun() { + constructor(x: X, name: String = ""): this(name) + + override val bindings: Bindings = Bindings(mapOf(this to this)) + override fun equals(other: Any?) = other is SVar<*> && name == other.name + override fun hashCode(): Int = name.hashCode() + operator fun getValue(thisRef: Any?, property: KProperty<*>) = + SVar(name.ifEmpty { property.name }) +} + +open class SConst> +constructor(open val value: Number): SFun(), Constant { + override fun toString() = value.toString() + override fun equals(other: Any?) = + if (other is SConst<*>) value == other.value else super.equals(other) + + override fun hashCode() = value.hashCode() + + open val doubleValue: Double by lazy { value.toDouble() } + + override fun times(multiplicand: VFun): VFun = + when (multiplicand) { + is Vec -> Vec(multiplicand.contents.map { this * it }) + else -> super.times(multiplicand) + } + + @Suppress("UNCHECKED_CAST") + override fun times(multiplicand: MFun) = + when (multiplicand) { + is Mat -> Mat(multiplicand.rows.map { this * it } as List>) + else -> super.times(multiplicand) + } + + // TODO: Think more carefully about how to do this for other number systems. + // Might need to push down to implementation when trigonometry is undefined. + override fun sin() = wrap(sin(doubleValue)) + override fun cos() = wrap(cos(doubleValue)) + override fun tan() = wrap(tan(doubleValue)) + override fun sqrt() = wrap(sqrt(doubleValue)) + + override fun unaryMinus() = wrap(-doubleValue) + + /** + * Constant propagation. + */ + + override fun log(base: SFun) = when (base) { + is SConst -> wrap(log(doubleValue, base.doubleValue)) + else -> super.log(base) + } + + override fun plus(addend: SFun) = when (addend) { + is SConst -> wrap(doubleValue + addend.doubleValue) + else -> super.plus(addend) + } + + override fun times(multiplicand: SFun) = when (multiplicand) { + is SConst -> wrap(doubleValue * multiplicand.doubleValue) + else -> super.times(multiplicand) + } + + override fun pow(exponent: SFun) = when (exponent) { + is SConst -> wrap(doubleValue.pow(exponent.doubleValue)) + else -> super.pow(exponent) + } +} + +sealed class Special>(override val value: Number): SConst(value) { + override fun toString() = this::class.simpleName!! +} + +class It>: Special(NaN) +class Zero>: Special(0.0) +class One>: Special(1.0) +class Two>: Special(2.0) +class E>: Special(E) + +// TODO: RationalNumber, ComplexNumber, Quaternion +abstract class RealNumber, Y: Number> +constructor(override val value: Y): SConst(value) { + override fun toString() = value.toString() + abstract override fun wrap(number: Number): SConst +} + +open class DReal(override val value: Double): RealNumber(value) { + override fun wrap(number: Number) = DReal(number.toDouble()) + + companion object: DReal(NaN) +} + +/** + * Extensions to convert numerical types from host language to eDSL. + */ + +fun > X.Var(): SVar = SVar() +fun > X.Var(e: Nat): VVar = VVar(e) +fun > X.Var(r: Nat, c: Nat): MVar = MVar(r, c) + +fun > X.Mat(r: Nat, c: Nat, gen: (Int, Int) -> Any): Mat = + (0 until r.i).map { i -> (0 until c.i).map { j -> wrapOrError(gen(i, j)) as SFun } } + .map { Vec(it) }.let { Mat(it) } + +fun > X.Vec(e: Nat, gen: (Int) -> Any): Vec = + Vec(List(e.i) { wrapOrError(gen(it)) as SFun }) + +operator fun > Number.times(multiplicand: SFun) = multiplicand.wrap(this) * multiplicand +operator fun , E: D1> Number.times(multiplicand: VFun): VFun = multiplicand.wrap(this) * multiplicand +operator fun , R: D1, C: D1> Number.times(multiplicand: MFun): MFun = multiplicand.wrap(this) * multiplicand +operator fun > Number.div(divisor: SFun) = divisor.wrap(this) / divisor +operator fun > Number.plus(addend: SFun) = addend.wrap(this) + addend +operator fun > Number.minus(subtrahend: SFun) = subtrahend.wrap(this) - subtrahend + +fun > Number.pow(exp: SFun) = exp.wrap(this) pow exp +fun > pow(base: SFun, exp: Number) = base pow base.wrap(exp) + +fun > SFun.toDouble() = + try { + (this as SConst).doubleValue + } catch (e: ClassCastException) { + //show("before") + e.printStackTrace() + throw NumberFormatException("Scalar function ${this::class.simpleName} has unbound free variables: ${bindings.allFreeVariables.keys}: $this") + } + +fun > d(fn: SFun) = Differential(fn) +class IndVar> constructor(val fn: SFun) + +class Differential>(private val fx: SFun) { + // TODO: ensure correctness for arbitrary nested functions using the Chain rule + infix operator fun div(arg: Differential) = fx.d(arg.fx.bindings.sVars.first()) +} + +//TODO: Figure out how to incorporate functions R -> R into type system +//@JvmName("infxsin") fun sin(angle: SFun): SFun = angle.sin() +//@JvmName("infxcos") fun cos(angle: SFun): SFun = angle.cos() +//@JvmName("infxtan") fun tan(angle: SFun): SFun = angle.tan() +//@JvmName("psfxsin") fun SFun.sin(): SFun = Sine(this) +//@JvmName("psfxcos") fun SFun.cos(): SFun = Cosine(this) +//@JvmName("psfxtan") fun SFun.tan(): SFun = Tangent(this) +// +//sealed class TrigFun +//constructor(override val input: SFun): +// SFun(input), UnFun { +// override fun d(v: SVar) = when (this) { +// is Sine -> input.cos() * input.d(v) +// is Cosine -> -input.sin() * input.d(v) +// is Tangent -> (input.cos() pow -TWO) * input.d(v) +// } +//} +// +//class Sine(override val input: SFun): TrigFun(input) +//class Cosine(override val input: SFun): TrigFun(input) +//class Tangent(override val input: SFun): TrigFun(input) + +fun > sin(angle: SFun) = angle.sin() +fun > cos(angle: SFun) = angle.cos() +fun > tan(angle: SFun) = angle.tan() +fun > exp(exponent: SFun) = exponent.exp() +fun > sqrt(radicand: SFun) = radicand.sqrt() + +operator fun Number.invoke(vararg numbers: Number) = this + /* * Algebraic primitives. * diff --git a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Vector.kt b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Vector.kt similarity index 99% rename from core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Vector.kt rename to core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Vector.kt index f8dee963..7a6631fe 100644 --- a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Vector.kt +++ b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/api/Vector.kt @@ -3,8 +3,9 @@ package ai.hypergraph.kotlingrad.api import ai.hypergraph.kaliningraph.circuits.* +import ai.hypergraph.kaliningraph.dot import ai.hypergraph.kotlingrad.shapes.* -import ai.hypergraph.kaliningraph.* +import ai.hypergraph.kotlingrad.EAGER import kotlin.reflect.KProperty /** @@ -23,7 +24,7 @@ sealed class VFun, E: D1>(override vararg val inputs: Fun): Fun try { it as Vec } catch (e: ClassCastException) { - show("before"); it.show("after") + //show("before"); it.show("after") throw NumberFormatException("Vector function has unbound free variables: ${bindings.allFreeVariables.keys}") } } diff --git a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/shapes/Shapes.kt b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/shapes/Shapes.kt similarity index 100% rename from core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/shapes/Shapes.kt rename to core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/shapes/Shapes.kt diff --git a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/typelevel/VariableCapture.kt b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/typelevel/VariableCapture.kt similarity index 100% rename from core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/typelevel/VariableCapture.kt rename to core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/typelevel/VariableCapture.kt diff --git a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/typelevel/Variables.kt b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/typelevel/Variables.kt similarity index 97% rename from core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/typelevel/Variables.kt rename to core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/typelevel/Variables.kt index 15ccf4a1..a3620592 100644 --- a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/typelevel/Variables.kt +++ b/core/src/commonMain/kotlin/ai/hypergraph/kotlingrad/typelevel/Variables.kt @@ -3,7 +3,7 @@ package ai.hypergraph.kotlingrad.typelevel import ai.hypergraph.kaliningraph.circuits.* -import ai.hypergraph.kotlingrad.typelevel.* +import kotlin.jvm.JvmName typealias OOO = Ex typealias OOX = Ex @@ -91,22 +91,22 @@ operator fun Ex.times(n: N) = Ex operator fun N.div(e: Ex) = Ex(Ops.ratio, null, Nt(this), e) operator fun Ex.div(n: N) = Ex(Ops.ratio, null, this, Nt(n)) -@JvmName("i:__t") operator fun OOX.invoke(v3: V3Bnd) = call(v3) -@JvmName("i:_t_") operator fun OXO.invoke(v2: V2Bnd) = call(v2) +@JvmName("i:__t") operator fun OOX.invoke(v3: V3Bnd) = call(v3) +@JvmName("i:_t_") operator fun OXO.invoke(v2: V2Bnd) = call(v2) @JvmName("i:_tt") operator fun OXX.invoke(v2: V2Bnd) = inv(v2) @JvmName("i:_tt") operator fun OXX.invoke(v3: V3Bnd) = inv(v3) -@JvmName("i:_tt") operator fun OXX.invoke(v2: V2Bnd, v3: V3Bnd) = call(v2, v3) -@JvmName("i:t__") operator fun XOO.invoke(v1: V1Bnd) = call(v1) +@JvmName("i:_tt") operator fun OXX.invoke(v2: V2Bnd, v3: V3Bnd) = call(v2, v3) +@JvmName("i:t__") operator fun XOO.invoke(v1: V1Bnd) = call(v1) @JvmName("i:t_t") operator fun XOX.invoke(v1: V1Bnd) = inv(v1) @JvmName("i:t_t") operator fun XOX.invoke(v3: V3Bnd) = inv(v3) -@JvmName("i:t_t") operator fun XOX.invoke(v1: V1Bnd, v3: V3Bnd) = call(v1, v3) +@JvmName("i:t_t") operator fun XOX.invoke(v1: V1Bnd, v3: V3Bnd) = call(v1, v3) @JvmName("i:tt_") operator fun XXO.invoke(v1: V1Bnd) = inv(v1) @JvmName("i:tt_") operator fun XXO.invoke(v2: V2Bnd) = inv(v2) -@JvmName("i:tt_") operator fun XXO.invoke(v1: V1Bnd, v2: V2Bnd) = call(v1, v2) +@JvmName("i:tt_") operator fun XXO.invoke(v1: V1Bnd, v2: V2Bnd) = call(v1, v2) @JvmName("i:ttt") operator fun XXX.invoke(v1: V1Bnd) = inv(v1) @JvmName("i:ttt") operator fun XXX.invoke(v2: V2Bnd) = inv(v2) @JvmName("i:ttt") operator fun XXX.invoke(v1: V1Bnd, v2: V2Bnd) = inv(v1, v2) @JvmName("i:ttt") operator fun XXX.invoke(v3: V3Bnd) = inv(v3) @JvmName("i:ttt") operator fun XXX.invoke(v1: V1Bnd, v3: V3Bnd) = inv(v1, v3) @JvmName("i:ttt") operator fun XXX.invoke(v2: V2Bnd, v3: V3Bnd) = inv(v2, v3) -@JvmName("i:ttt") operator fun XXX.invoke(v1: V1Bnd, v2: V2Bnd, v3: V3Bnd) = call(v1, v2, v3) \ No newline at end of file +@JvmName("i:ttt") operator fun XXX.invoke(v1: V1Bnd, v2: V2Bnd, v3: V3Bnd) = call(v1, v2, v3) \ No newline at end of file diff --git a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Scalar.kt b/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Scalar.kt deleted file mode 100644 index 76c6b750..00000000 --- a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Scalar.kt +++ /dev/null @@ -1,471 +0,0 @@ -@file:Suppress("FunctionName", "LocalVariableName", "unused", "UNUSED_VARIABLE") - -package ai.hypergraph.kotlingrad.api - -import ai.hypergraph.kaliningraph.circuits.* -import ai.hypergraph.kotlingrad.shapes.* -import kotlin.Double.Companion.NaN -import kotlin.math.* -import kotlin.reflect.KProperty - -/** - * Interface representing a generic mathematical function. - * - * TODO: Implement proper monad like [java.util.function.Function] or [Function] - */ - -interface Fun>: (Bindings) -> Fun { - val inputs: Array> - val bindings: Bindings - get() = Bindings(*inputs) - val op: Op - - fun isConstant(): Boolean = bindings.allVars.isEmpty() - fun wrap(number: Number): SConst = SConst(number.toDouble()) - - override operator fun invoke(newBindings: Bindings): Fun - operator fun invoke(): Fun - operator fun invoke(vararg numbers: Number): Fun = - invoke(bindings.zip(numbers.map { wrap(it) })) - - operator fun invoke(vararg funs: Fun): Fun = invoke(bindings.zip(funs.toList())) - - operator fun invoke(vararg ps: FunToAny): Fun = invoke(ps.toList().bind()) - - fun toGate(): Gate = when (this) { - is NilFun -> Gate.wrap(this) - is UnFun -> Gate(op, input.toGate()) - is BiFun -> Gate(op, left.toGate(), right.toGate()) - is PolyFun -> Gate(op, *inputs.map { it.toGate() }.toTypedArray()) - else -> TODO(this::class.simpleName!!) - } - - fun toGraph() = toGate().graph - - fun List>.bind() = Bindings(associate { it.first to wrapOrError(it.second) }) - - fun wrapOrError(any: Any): Fun = when (any) { - is Fun<*> -> any as Fun - is Number -> wrap(any) - is List<*> -> when { - any.isEmpty() -> throw Exception("Empty collection") - any.first() is Number -> Vec(any.map { wrap(it as Number) }) - else -> TODO() // else if(any.first() is List<*>) Mat() - } - is Array<*> -> wrapOrError(any.toList()) - else -> throw NumberFormatException("Invoke expects a number or function but got: $any") - } - - fun asString(): String = when (this) { - is Constant -> "$this" - is Variable -> "Var($name)" - is Grad -> "d($input) / d($vrb)" - is SComposition -> "($input)$bindings" - is Power<*> -> "($left).$op($right)" //TODO: separate asString() and toCode() - is BiFun<*> -> "($left) $op ($right)" - is UnFun<*> -> "$op($input)" - is PolyFun<*> -> "$op$inputs" - else -> this::class.simpleName!! - } -} - -// https://arxiv.org/pdf/2001.02209.pdf - -// Describes the arity of the operator - -interface NilFun>: Fun - -interface UnFun>: PolyFun { - val input: Fun -} - -interface BiFun>: PolyFun { - val left: Fun - val right: Fun -} - -interface PolyFun>: Fun { - override val inputs: Array> -} - -interface Grad>: BiFun { - val input: Fun - val vrb: Variable - override val left: Fun - get() = input - override val right: Fun - get() = vrb -} - -interface Variable>: Fun, NilFun { - val name: String -} - -interface Constant>: Fun, NilFun - -/** - * Scalar function. - */ - -sealed class SFun> -constructor(override vararg val inputs: Fun): PolyFun, Field> { - val ZERO: Special by lazy { Zero() } - val ONE: Special by lazy { One() } - val TWO: Special by lazy { Two() } - val E: Special by lazy { E() } - - override fun plus(addend: SFun): SFun = Sum(this, addend) - override fun times(multiplicand: SFun): SFun = Prod(this, multiplicand) - override fun div(divisor: SFun): SFun = this * divisor.pow(-ONE) - open operator fun times(multiplicand: VFun): VFun = SVProd(this, multiplicand) - open operator fun times(multiplicand: MFun): MFun = SMProd(this, multiplicand) - - /** - * TODO: Parameterize operator in constructor instead of using subtyping, - * this would allow us to migrate from subclass to operator matching [Gate]. - */ - - class AOP>(val op: Op, val of: (Fun) -> SFun) - - // TODO: Implement a proper curry and lower variadic apply onto it. - fun apply(op: Op): (SFun) -> SFun = when (op) { - Ops.sum -> { it: SFun -> this + it } - Ops.prod -> { it: SFun -> this * it } - else -> TODO(op::class.simpleName!!) - } - - /** - * TODO: Figure out how to avoid casting. Once stable, port to [VFun], [MFun]. - */ - - @Suppress("UNCHECKED_CAST") - fun apply(vararg xs: Fun): SFun = when (op) { - Ops.id -> this - Ops.sin -> (xs[0] as SFun).sin() - Ops.cos -> (xs[0] as SFun).cos() - Ops.tan -> (xs[0] as SFun).tan() - Ops.sub -> -(xs[0] as SFun) - - Ops.d -> TODO() - Ops.sum -> (xs[0] as SFun) + xs[1] as SFun - Ops.prod -> (xs[0] as SFun) * xs[1] as SFun - Ops.pow -> (xs[0] as SFun) pow xs[1] as SFun - Ops.log -> (xs[0] as SFun).log(xs[1] as SFun) - Ops.dot -> (xs[0] as VFun) dot xs[1] as VFun - - Ops.Σ -> (xs[0] as VFun).sum() - Ops.λ -> TODO() - else -> TODO(op::class.simpleName!!) - } - - override val op: Op = when (this) { - is SVar -> Ops.id - is SConst -> Ops.id - is Sine -> Ops.sin - is Cosine -> Ops.cos - is Tangent -> Ops.tan - is Negative -> Ops.sub - - is Sum -> Ops.sum - is Prod -> Ops.prod - is Power -> Ops.pow - is Log -> Ops.log - is Derivative -> Ops.d - is DProd -> Ops.dot - - is SComposition -> Ops.λ - is VSumAll -> Ops.Σ - } - - override fun invoke(newBindings: Bindings): SFun = - SComposition(this, newBindings).run { - if (bindings.complete || newBindings.readyToBind || EAGER) evaluate else this - } - - override operator fun invoke(): SFun = SComposition(this).evaluate - override operator fun invoke(vararg numbers: Number): SFun = - invoke(bindings.zip(numbers.map { wrap(it) })) - - override operator fun invoke(vararg funs: Fun): SFun = - invoke(bindings.zip(funs.toList())) - - override operator fun invoke(vararg ps: FunToAny): SFun = - invoke(ps.toList().bind()) - - open fun d(v1: SVar): SFun = - Derivative(this, v1)//.let { if (EAGER) it.df() else it } - - open fun sin(): SFun = Sine(this) - open fun cos(): SFun = Cosine(this) - open fun tan(): SFun = Tangent(this) - fun exp(): SFun = Power(E, this) - - open fun d(vVar: VVar): VFun = - Gradient(this, vVar)//.let { if(EAGER) it.df() else it } - - open fun d(mVar: MVar): MFun = - MGradient(this, mVar)//.let { if(EAGER) it.df() else it } - - open fun grad(): Map, SFun> = - bindings.sVars.associateWith { Derivative(this, it) } - - fun ln() = log(E) - override fun log(base: SFun): SFun = Log(this, base) - override fun pow(exponent: SFun): SFun = Power(this, exponent) - override fun unaryMinus(): SFun = Negative(this) - override fun unaryPlus(): SFun = this - open fun sqrt(): SFun = this pow (ONE / TWO) - - operator fun div(divisor: Number): SFun = this / wrap(divisor) - operator fun plus(addend: Number): SFun = this + wrap(addend) - operator fun minus(subtrahend: Number): SFun = this - wrap(subtrahend) - operator fun times(multiplicand: Number): SFun = this * wrap(multiplicand) - infix fun pow(exp: Number): SFun = this pow wrap(exp) - - override fun toString() = when (this) { - is SVar -> name - is SComposition -> "($input)$bindings" - else -> asString() - } - - // TODO: Implement symbolic dis/unification - override fun equals(other: Any?) = super.equals(other) -} - -/** - * Symbolic operators. - */ - -class Sine>(override val input: SFun): SFun(input), UnFun -class Cosine>(override val input: SFun): SFun(input), UnFun -class Tangent>(override val input: SFun): SFun(input), UnFun -class Negative>(override val input: SFun): SFun(input), UnFun -class Sum>(override val left: SFun, override val right: SFun): SFun(left, right), BiFun -class Prod>(override val left: SFun, override val right: SFun): SFun(left, right), BiFun -class Power>(override val left: SFun, override val right: SFun): SFun(left, right), BiFun -class Log>(override val left: SFun, override val right: SFun = E()): SFun(left, right), BiFun - -class Derivative> constructor( - override val input: SFun, - override val vrb: SVar -): SFun(input, vrb), Grad { - fun df() = input.df() - - @Suppress("UNCHECKED_CAST") - fun SFun.df(): SFun = when (this@df) { - is SVar -> if (this == vrb) ONE else ZERO - is SConst -> ZERO - is Sum -> left.df() + right.df() - is Prod -> left.df() * right + left * right.df() - is Power -> - //https://en.wikipedia.org/wiki/Differentiation_rules#The_polynomial_or_elementary_power_rule - if (right.isConstant()) right * left.pow(right - ONE) * left.df() - //https://en.wikipedia.org/wiki/Differentiation_rules#Generalized_power_rule - else this * (left.df() * right / left + right.df() * left.ln()) - is Negative -> -input.df() - is Log -> (left pow -ONE) * left.df() - is Sine -> input.cos() * input.df() - is Cosine -> -input.sin() * input.df() - is Tangent -> (input.cos() pow -TWO) * input.df() - is Derivative -> input.df().df() - is DProd -> (left.d(vrb) as VFun dot right as VFun) + (left as VFun dot right.d(vrb)) - is SComposition -> evaluate.df() - is VSumAll -> input.d(vrb).sum() -// is Custom -> fn.df() - } -} - -class SComposition> constructor( - override val input: SFun, - arguments: Bindings = Bindings(input) -): SFun(input), UnFun { - override val bindings: Bindings = input.bindings + arguments - val evaluate: SFun by lazy { bind(bindings) } - - // TODO: Look into deep recursion so that we don't blow the stack - // https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-deep-recursive-function - // https://medium.com/@elizarov/deep-recursion-with-coroutines-7c53e15993e3 - - fun SFun.bind(bnds: Bindings): SFun = - bnds[this@bind] ?: when (this@bind) { - is Derivative -> df().bind(bnds) - // TODO: should we really be merging bindings for nested composition? - is SComposition -> input.bind(bnds + bindings) - else -> apply(*inputs.map { - if (it is SFun) it.bind(bnds) else it(bnds) - }.toTypedArray()) - } //.also { result -> bnds.checkForUnpropagatedVariables(this@bind, result) } - //appl(*inputs.map { it.bind(bnds) }.toTypedArray())) as SFun -} - -class DProd> constructor( - override val left: VFun, - override val right: VFun -): SFun(left, right), BiFun - -class VSumAll, E: D1> -constructor(val input: VFun): SFun(input), PolyFun { - override val inputs: Array> = arrayOf(input) -} - -class SVar>(override val name: String = ""): Variable, SFun() { - constructor(x: X, name: String = ""): this(name) - - override val bindings: Bindings = Bindings(mapOf(this to this)) - override fun equals(other: Any?) = other is SVar<*> && name == other.name - override fun hashCode(): Int = name.hashCode() - operator fun getValue(thisRef: Any?, property: KProperty<*>) = - SVar(name.ifEmpty { property.name }) -} - -open class SConst> -constructor(open val value: Number): SFun(), Constant { - override fun toString() = value.toString() - override fun equals(other: Any?) = - if (other is SConst<*>) value == other.value else super.equals(other) - - override fun hashCode() = value.hashCode() - - open val doubleValue: Double by lazy { value.toDouble() } - - override fun times(multiplicand: VFun): VFun = - when (multiplicand) { - is Vec -> Vec(multiplicand.contents.map { this * it }) - else -> super.times(multiplicand) - } - - @Suppress("UNCHECKED_CAST") - override fun times(multiplicand: MFun) = - when (multiplicand) { - is Mat -> Mat(multiplicand.rows.map { this * it } as List>) - else -> super.times(multiplicand) - } - - // TODO: Think more carefully about how to do this for other number systems. - // Might need to push down to implementation when trigonometry is undefined. - override fun sin() = wrap(sin(doubleValue)) - override fun cos() = wrap(cos(doubleValue)) - override fun tan() = wrap(tan(doubleValue)) - override fun sqrt() = wrap(sqrt(doubleValue)) - - override fun unaryMinus() = wrap(-doubleValue) - - /** - * Constant propagation. - */ - - override fun log(base: SFun) = when (base) { - is SConst -> wrap(log(doubleValue, base.doubleValue)) - else -> super.log(base) - } - - override fun plus(addend: SFun) = when (addend) { - is SConst -> wrap(doubleValue + addend.doubleValue) - else -> super.plus(addend) - } - - override fun times(multiplicand: SFun) = when (multiplicand) { - is SConst -> wrap(doubleValue * multiplicand.doubleValue) - else -> super.times(multiplicand) - } - - override fun pow(exponent: SFun) = when (exponent) { - is SConst -> wrap(doubleValue.pow(exponent.doubleValue)) - else -> super.pow(exponent) - } -} - -sealed class Special>(override val value: Number): SConst(value) { - override fun toString() = this::class.simpleName!! -} - -class It>: Special(NaN) -class Zero>: Special(0.0) -class One>: Special(1.0) -class Two>: Special(2.0) -class E>: Special(E) - -// TODO: RationalNumber, ComplexNumber, Quaternion -abstract class RealNumber, Y: Number> -constructor(override val value: Y): SConst(value) { - override fun toString() = value.toString() - abstract override fun wrap(number: Number): SConst -} - -open class DReal(override val value: Double): RealNumber(value) { - override fun wrap(number: Number) = DReal(number.toDouble()) - - companion object: DReal(NaN) -} - -/** - * Extensions to convert numerical types from host language to eDSL. - */ - -fun > X.Var(): SVar = SVar() -fun > X.Var(e: Nat): VVar = VVar(e) -fun > X.Var(r: Nat, c: Nat): MVar = MVar(r, c) - -fun > X.Mat(r: Nat, c: Nat, gen: (Int, Int) -> Any): Mat = - (0 until r.i).map { i -> (0 until c.i).map { j -> wrapOrError(gen(i, j)) as SFun } } - .map { Vec(it) }.let { Mat(it) } - -fun > X.Vec(e: Nat, gen: (Int) -> Any): Vec = - Vec(List(e.i) { wrapOrError(gen(it)) as SFun }) - -operator fun > Number.times(multiplicand: SFun) = multiplicand.wrap(this) * multiplicand -operator fun , E: D1> Number.times(multiplicand: VFun): VFun = multiplicand.wrap(this) * multiplicand -operator fun , R: D1, C: D1> Number.times(multiplicand: MFun): MFun = multiplicand.wrap(this) * multiplicand -operator fun > Number.div(divisor: SFun) = divisor.wrap(this) / divisor -operator fun > Number.plus(addend: SFun) = addend.wrap(this) + addend -operator fun > Number.minus(subtrahend: SFun) = subtrahend.wrap(this) - subtrahend - -fun > Number.pow(exp: SFun) = exp.wrap(this) pow exp -fun > pow(base: SFun, exp: Number) = base pow base.wrap(exp) - -fun > SFun.toDouble() = - try { - (this as SConst).doubleValue - } catch (e: ClassCastException) { - show("before") - e.printStackTrace() - throw NumberFormatException("Scalar function ${javaClass.simpleName} has unbound free variables: ${bindings.allFreeVariables.keys}: $this") - } - -fun > d(fn: SFun) = Differential(fn) -class IndVar> constructor(val fn: SFun) - -class Differential>(private val fx: SFun) { - // TODO: ensure correctness for arbitrary nested functions using the Chain rule - infix operator fun div(arg: Differential) = fx.d(arg.fx.bindings.sVars.first()) -} - -//TODO: Figure out how to incorporate functions R -> R into type system -//@JvmName("infxsin") fun sin(angle: SFun): SFun = angle.sin() -//@JvmName("infxcos") fun cos(angle: SFun): SFun = angle.cos() -//@JvmName("infxtan") fun tan(angle: SFun): SFun = angle.tan() -//@JvmName("psfxsin") fun SFun.sin(): SFun = Sine(this) -//@JvmName("psfxcos") fun SFun.cos(): SFun = Cosine(this) -//@JvmName("psfxtan") fun SFun.tan(): SFun = Tangent(this) -// -//sealed class TrigFun -//constructor(override val input: SFun): -// SFun(input), UnFun { -// override fun d(v: SVar) = when (this) { -// is Sine -> input.cos() * input.d(v) -// is Cosine -> -input.sin() * input.d(v) -// is Tangent -> (input.cos() pow -TWO) * input.d(v) -// } -//} -// -//class Sine(override val input: SFun): TrigFun(input) -//class Cosine(override val input: SFun): TrigFun(input) -//class Tangent(override val input: SFun): TrigFun(input) - -fun > sin(angle: SFun) = angle.sin() -fun > cos(angle: SFun) = angle.cos() -fun > tan(angle: SFun) = angle.tan() -fun > exp(exponent: SFun) = exponent.exp() -fun > sqrt(radicand: SFun) = radicand.sqrt() - -operator fun Number.invoke(vararg numbers: Number) = this \ No newline at end of file diff --git a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Utils.kt b/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Utils.kt index cc06de28..17551fed 100644 --- a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Utils.kt +++ b/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/api/Utils.kt @@ -15,6 +15,4 @@ fun Fun<*>.saveToFile(filename: String) = fun Fun<*>.render(format: Format = SVG) = toGraph().toGraphviz().render(format) -fun Fun<*>.show(name: String = "temp") = toGraph().show(name) - -var EAGER = false \ No newline at end of file +fun Fun<*>.show(name: String = "temp") = toGraph().show(name) \ No newline at end of file diff --git a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/notebook/KotlinJupyter.kt b/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/notebook/KotlinJupyter.kt index f3455fce..dd6cd811 100644 --- a/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/notebook/KotlinJupyter.kt +++ b/core/src/jvmMain/kotlin/ai/hypergraph/kotlingrad/notebook/KotlinJupyter.kt @@ -4,7 +4,7 @@ import ai.hypergraph.kaliningraph.circuits.Gate import ai.hypergraph.kaliningraph.html import ai.hypergraph.kaliningraph.image.matToBase64Img import ai.hypergraph.kaliningraph.tensor.* -import ai.hypergraph.kaliningraph.typefamily.* +import ai.hypergraph.kaliningraph.types.Graph import ai.hypergraph.kotlingrad.api.* import org.jetbrains.kotlinx.jupyter.api.HTML import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration diff --git a/kaliningraph b/kaliningraph index 84c7ab18..5d68c8dd 160000 --- a/kaliningraph +++ b/kaliningraph @@ -1 +1 @@ -Subproject commit 84c7ab18f5fb0482fc18b2b49f8c9ef4a3c7de15 +Subproject commit 5d68c8dd25b9fbce6e808bb6926e6053959e732b diff --git a/shipshape/src/main/kotlin/ai/hypergraph/shipshape/Shipshape.kt b/shipshape/src/main/kotlin/ai/hypergraph/shipshape/Shipshape.kt index 893e2470..1c891260 100644 --- a/shipshape/src/main/kotlin/ai/hypergraph/shipshape/Shipshape.kt +++ b/shipshape/src/main/kotlin/ai/hypergraph/shipshape/Shipshape.kt @@ -8,7 +8,7 @@ open class Shipshape: Plugin { project.run { tasks.register("genShapes") { // TODO: Parameterize this path - val outputDir = "$projectDir/src/jvmMain/kotlin/ai/hypergraph/kotlingrad" + val outputDir = "$projectDir/src/commonMain/kotlin/ai/hypergraph/kotlingrad" // TODO: Switch to commonMain // val outputDir = "$projectDir/src/commonMain/kotlin/ai/hypergraph/kotlingrad" try { diff --git a/shipshape/src/main/kotlin/ai/hypergraph/shipshape/VarGen.kt b/shipshape/src/main/kotlin/ai/hypergraph/shipshape/VarGen.kt index 6c1d51fa..fa34bbe3 100644 --- a/shipshape/src/main/kotlin/ai/hypergraph/shipshape/VarGen.kt +++ b/shipshape/src/main/kotlin/ai/hypergraph/shipshape/VarGen.kt @@ -10,7 +10,7 @@ fun genTypeLevelVariables() = """ package ai.hypergraph.kotlingrad.typelevel import ai.hypergraph.kaliningraph.circuits.* -import ai.hypergraph.kotlingrad.typelevel.* +import kotlin.jvm.JvmName ${genTypeAliases()} @@ -120,7 +120,7 @@ fun genInvokes(allFreeVariableConfigurations: Set> = allBinaryArra fvs.joinToString(", ") { "v$it: V${it}Bnd" } + ") = " + fvConfig.mapIndexed { i, b -> val isBound = (i + 1) in fvs; !(!b || isBound) }.joinToString("") { if (it) "X" else "O" } - .let { if (it == "OOO") "call" else "inv" } + + .let { if (it == "OOO") "call" else "inv" } + fvs.joinToString(", ", "(", ")") { "v$it" } } }