From 4d12f6ed2c4643e6c6795ba264a9e6567dbf194e Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 3 Sep 2025 19:16:53 +0200 Subject: [PATCH 001/196] feat: first basic dsl Add the simulation entry point for building dsl files, using Continuous2DEnvironment as default environment --- .../unibo/alchemist/boundary/dsl/DslLoader.kt | 28 +++++++++++++++++++ .../boundary/dsl/SimulationContext.kt | 25 +++++++++++++++++ .../boundary/dsl/model/Incarnation.kt | 16 +++++++++++ .../it/unibo/alchemist/dsl/TestLoader.kt | 27 ++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt new file mode 100644 index 0000000000..681daf00cd --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl + +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.core.Engine +import it.unibo.alchemist.core.Simulation +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.SupportedIncarnations +import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.positions.Euclidean2DPosition + +abstract class DslLoader(private val ctx: SimulationContext) : Loader { + @Suppress("UNCHECKED_CAST") + override fun > getWith(values: Map): Simulation { + val incarnation = SupportedIncarnations.get(ctx.incarnation.name).get() + val env = Continuous2DEnvironment(incarnation as Incarnation) + return Engine(env) as Simulation + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt new file mode 100644 index 0000000000..7851dbd64e --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt @@ -0,0 +1,25 @@ +package it.unibo.alchemist.boundary.dsl + +import it.unibo.alchemist.boundary.DependentVariable +import it.unibo.alchemist.boundary.Launcher +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.Variable +import it.unibo.alchemist.boundary.dsl.model.Incarnation +import it.unibo.alchemist.boundary.launchers.DefaultLauncher + +class SimulationContext { + var incarnation: Incarnation = Incarnation.SAPERE +} + +fun createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { + override val constants: Map = emptyMap() + override val dependentVariables: Map> = emptyMap() + override val variables: Map> = emptyMap() + override val remoteDependencies: List = emptyList() + override val launcher: Launcher = DefaultLauncher() +} + +fun simulation(block: SimulationContext.() -> Unit): Loader { + val sim = SimulationContext().apply(block) + return createLoader(sim) +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt new file mode 100644 index 0000000000..927558687e --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model +enum class Incarnation { + SAPERE, + PROTELIS, + SCAFI, + BIOCHEMISTRY, +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt new file mode 100644 index 0000000000..b6ef170e83 --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.boundary.dsl.model.Incarnation +import it.unibo.alchemist.boundary.dsl.simulation +import it.unibo.alchemist.model.SupportedIncarnations +import org.junit.jupiter.api.Test + +class TestLoader { + + @Test + fun testDsl() { + val loader = simulation { + incarnation = Incarnation.SAPERE + } + + loader.launch(loader.launcher) + } +} From d4e9faba9cd892049df5c1c025a9ce2d415d9350 Mon Sep 17 00:00:00 2001 From: marco Date: Thu, 4 Sep 2025 10:14:29 +0200 Subject: [PATCH 002/196] feat: add deployments dsl Introduce dsl support for defining deployments using any Deployment<*> type --- .../unibo/alchemist/boundary/dsl/DslLoader.kt | 23 +++++-- .../boundary/dsl/SimulationContext.kt | 21 +++++- .../boundary/dsl/model/DeploymentsContext.kt | 49 +++++++++++++ .../it/unibo/alchemist/dsl/TestDeployments.kt | 69 +++++++++++++++++++ .../it/unibo/alchemist/dsl/TestLoader.kt | 1 - 5 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt index 681daf00cd..7c28e4386d 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt @@ -12,17 +12,30 @@ package it.unibo.alchemist.boundary.dsl import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.core.Engine import it.unibo.alchemist.core.Simulation -import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.SupportedIncarnations -import it.unibo.alchemist.model.environments.Continuous2DEnvironment -import it.unibo.alchemist.model.positions.Euclidean2DPosition +import org.apache.commons.math3.random.MersenneTwister abstract class DslLoader(private val ctx: SimulationContext) : Loader { @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation { val incarnation = SupportedIncarnations.get(ctx.incarnation.name).get() - val env = Continuous2DEnvironment(incarnation as Incarnation) - return Engine(env) as Simulation + val randomGenerator = MersenneTwister(0) + val environment = ctx.environment as Environment + // Get deployments and add nodes + val deployments = ctx.ctxDeploy.deployments + deployments.forEach { deployment -> + deployment.forEach { position -> + val node = incarnation.createNode( + randomGenerator, + environment, + null, + ) + environment.addNode(node, position as P) + } + } + + return Engine(environment) } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt index 7851dbd64e..80b394cab6 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt @@ -4,11 +4,28 @@ import it.unibo.alchemist.boundary.DependentVariable import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.model.Incarnation +import it.unibo.alchemist.boundary.dsl.model.DeploymentsContext +import it.unibo.alchemist.boundary.dsl.model.Incarnation as Inc import it.unibo.alchemist.boundary.launchers.DefaultLauncher +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.SupportedIncarnations +import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.positions.Euclidean2DPosition class SimulationContext { - var incarnation: Incarnation = Incarnation.SAPERE + var incarnation: Inc = Inc.SAPERE + var environment: Environment<*, *> = defaultEnvironment() + val ctxDeploy: DeploymentsContext = DeploymentsContext(this) + + @Suppress("UNCHECKED_CAST") + private fun defaultEnvironment(): Environment<*, Euclidean2DPosition> { + val inc = SupportedIncarnations.get(incarnation.name).get() + return Continuous2DEnvironment(inc) + } + + fun deployments(block: DeploymentsContext.() -> Unit) { + ctxDeploy.apply(block) + } } fun createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt new file mode 100644 index 0000000000..40ddc635f8 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.dsl.SimulationContext +import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.deployments.Grid +import it.unibo.alchemist.model.deployments.Point +import org.apache.commons.math3.random.MersenneTwister +import org.apache.commons.math3.random.RandomGenerator + +class DeploymentsContext(private val ctx: SimulationContext) { + var deployments: MutableList> = mutableListOf() + var generator: RandomGenerator = MersenneTwister(0) + + fun deploy(deployment: Deployment<*>) { + deployments.add(deployment) + } + + // Convenience methods to avoid casting issues + fun point(x: Double, y: Double) { + val point = Point(ctx.environment, x, y) + deploy(point) + } + + fun grid( + xStart: Double, + yStart: Double, + xEnd: Double, + yEnd: Double, + xStep: Double, + yStep: Double, + xRand: Double = 0.0, + yRand: Double = 0.0, + ) { + val grid = Grid( + ctx.environment, generator, xStart, + yStart, xEnd, yEnd, xStep, yStep, xRand, yRand, + ) + deploy(grid) + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt new file mode 100644 index 0000000000..5ddb29c9fe --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.boundary.dsl.model.Incarnation +import it.unibo.alchemist.boundary.dsl.simulation +import it.unibo.alchemist.model.deployments.Grid +import it.unibo.alchemist.model.deployments.Point +import org.junit.jupiter.api.Test + +class TestDeployments { + + @Test + fun testDeployments() { + val loader = simulation { + incarnation = Incarnation.SAPERE + deployments { + point(0.0, 0.0) + } + } + + loader.launch(loader.launcher) + } + + @Test + fun testMultipleDeployments() { + val loader = simulation { + incarnation = Incarnation.SAPERE + deployments { + val point = Point(environment, 0.0, 0.0) + deploy(point) + + point(1.0, 1.0) + } + } + + loader.launch(loader.launcher) + } + + @Test + fun testGridDeployment() { + val loader = simulation { + incarnation = Incarnation.SAPERE + deployments { + val grid = Grid( + environment, + generator, + 1.0, + 1.0, + 5.0, + 5.0, + 1.0, + 1.0, + ) + deploy(grid) + grid(1.0, 1.0, 5.0, 5.0, 1.0, 1.0) + } + } + + loader.launch(loader.launcher) + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt index b6ef170e83..3b61a82aa1 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt @@ -11,7 +11,6 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.model.Incarnation import it.unibo.alchemist.boundary.dsl.simulation -import it.unibo.alchemist.model.SupportedIncarnations import org.junit.jupiter.api.Test class TestLoader { From 47064ef432e54fc09e7d0b8cb6228342f15f0021 Mon Sep 17 00:00:00 2001 From: marco Date: Thu, 4 Sep 2025 12:59:13 +0200 Subject: [PATCH 003/196] refactor: handle generic types --- .../unibo/alchemist/boundary/dsl/DslLoader.kt | 4 +- .../boundary/dsl/SimulationContext.kt | 23 +++++----- .../boundary/dsl/model/DeploymentsContext.kt | 34 +++----------- .../boundary/dsl/model/EnvironmentContext.kt | 31 +++++++++++++ .../it/unibo/alchemist/dsl/TestDeployments.kt | 44 ++++++++++--------- .../dsl/{TestLoader.kt => TestSimulations.kt} | 17 ++++++- 6 files changed, 89 insertions(+), 64 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/{TestLoader.kt => TestSimulations.kt} (63%) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt index 7c28e4386d..aefe1100ff 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt @@ -22,9 +22,9 @@ abstract class DslLoader(private val ctx: SimulationContext) : Loader { override fun > getWith(values: Map): Simulation { val incarnation = SupportedIncarnations.get(ctx.incarnation.name).get() val randomGenerator = MersenneTwister(0) - val environment = ctx.environment as Environment + val environment = ctx.envCtx?.environment as Environment // Get deployments and add nodes - val deployments = ctx.ctxDeploy.deployments + val deployments = ctx.envCtx?.ctxDeploy?.deployments ?: emptyList() deployments.forEach { deployment -> deployment.forEach { position -> val node = incarnation.createNode( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt index 80b394cab6..d41130a1f1 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt @@ -4,28 +4,29 @@ import it.unibo.alchemist.boundary.DependentVariable import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.model.DeploymentsContext +import it.unibo.alchemist.boundary.dsl.model.EnvironmentContext import it.unibo.alchemist.boundary.dsl.model.Incarnation as Inc import it.unibo.alchemist.boundary.launchers.DefaultLauncher import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.SupportedIncarnations import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.positions.Euclidean2DPosition +import kotlin.jvm.optionals.getOrElse class SimulationContext { var incarnation: Inc = Inc.SAPERE - var environment: Environment<*, *> = defaultEnvironment() - val ctxDeploy: DeploymentsContext = DeploymentsContext(this) + var envCtx: EnvironmentContext<*, *>? = null - @Suppress("UNCHECKED_CAST") - private fun defaultEnvironment(): Environment<*, Euclidean2DPosition> { - val inc = SupportedIncarnations.get(incarnation.name).get() - return Continuous2DEnvironment(inc) - } - - fun deployments(block: DeploymentsContext.() -> Unit) { - ctxDeploy.apply(block) + fun getDefault(): Environment = Continuous2DEnvironment(this.getIncarnation()) + fun > environment(env: Environment, block: EnvironmentContext.() -> Unit) { + envCtx = EnvironmentContext(this, env).apply(block) } + internal fun > getIncarnation(): Incarnation = + SupportedIncarnations.get(incarnation.name).getOrElse { + throw IllegalArgumentException("Incarnation $incarnation not supported for the given types") + } } fun createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index 40ddc635f8..f7ecb62b02 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -9,41 +9,17 @@ package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.boundary.dsl.SimulationContext import it.unibo.alchemist.model.Deployment -import it.unibo.alchemist.model.deployments.Grid -import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.Position import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator -class DeploymentsContext(private val ctx: SimulationContext) { - var deployments: MutableList> = mutableListOf() +class DeploymentsContext>(private val ctx: EnvironmentContext) { + var deployments: MutableList> = mutableListOf() var generator: RandomGenerator = MersenneTwister(0) fun deploy(deployment: Deployment<*>) { - deployments.add(deployment) - } - - // Convenience methods to avoid casting issues - fun point(x: Double, y: Double) { - val point = Point(ctx.environment, x, y) - deploy(point) - } - - fun grid( - xStart: Double, - yStart: Double, - xEnd: Double, - yEnd: Double, - xStep: Double, - yStep: Double, - xRand: Double = 0.0, - yRand: Double = 0.0, - ) { - val grid = Grid( - ctx.environment, generator, xStart, - yStart, xEnd, yEnd, xStep, yStep, xRand, yRand, - ) - deploy(grid) + @Suppress("UNCHECKED_CAST") + deployments.add(deployment as Deployment

) } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt new file mode 100644 index 0000000000..165fa1f03d --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.dsl.SimulationContext +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.LinkingRule +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.SupportedIncarnations +import it.unibo.alchemist.model.linkingrules.NoLinks + +class EnvironmentContext>(private val ctx: SimulationContext, env: Environment) { + val environment: Environment = env + var networkModel: LinkingRule = NoLinks() + val ctxDeploy: DeploymentsContext = DeploymentsContext(this) + + val incarnation: Incarnation + get() = SupportedIncarnations.get(ctx.incarnation.name).get() + + fun deployments(block: DeploymentsContext.() -> Unit) { + ctxDeploy.apply(block) + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index 5ddb29c9fe..1323a08aaf 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -21,8 +21,10 @@ class TestDeployments { fun testDeployments() { val loader = simulation { incarnation = Incarnation.SAPERE - deployments { - point(0.0, 0.0) + environment(getDefault()) { + deployments { + Point(environment, 0.0, 0.0) + } } } @@ -33,11 +35,12 @@ class TestDeployments { fun testMultipleDeployments() { val loader = simulation { incarnation = Incarnation.SAPERE - deployments { - val point = Point(environment, 0.0, 0.0) - deploy(point) - - point(1.0, 1.0) + environment(getDefault()) { + deployments { + val point = Point(environment, 0.0, 0.0) + deploy(point) + deploy(Point(environment, 1.0, 1.0)) + } } } @@ -48,19 +51,20 @@ class TestDeployments { fun testGridDeployment() { val loader = simulation { incarnation = Incarnation.SAPERE - deployments { - val grid = Grid( - environment, - generator, - 1.0, - 1.0, - 5.0, - 5.0, - 1.0, - 1.0, - ) - deploy(grid) - grid(1.0, 1.0, 5.0, 5.0, 1.0, 1.0) + environment(getDefault()) { + deployments { + val grid = Grid( + environment, + generator, + 1.0, + 1.0, + 5.0, + 5.0, + 1.0, + 1.0, + ) + deploy(grid) + } } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt similarity index 63% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt index 3b61a82aa1..3c49be10e4 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestLoader.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt @@ -11,16 +11,29 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.model.Incarnation import it.unibo.alchemist.boundary.dsl.simulation +import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import org.junit.jupiter.api.Test -class TestLoader { +class TestSimulations { @Test - fun testDsl() { + fun testIncarnation() { val loader = simulation { incarnation = Incarnation.SAPERE } loader.launch(loader.launcher) } + + @Test + fun testLinkingRule() { + val loader = simulation { + incarnation = Incarnation.SAPERE + environment(getDefault()) { + networkModel = ConnectWithinDistance(5.0) + } + } + + loader.launch(loader.launcher) + } } From 4956fd516dd0d9728b6e8ed19dfc093e70abe612 Mon Sep 17 00:00:00 2001 From: marco Date: Fri, 5 Sep 2025 11:51:35 +0200 Subject: [PATCH 004/196] feat: add contents handling add dsl support for defining contents inside a deployment --- .../unibo/alchemist/boundary/dsl/DslLoader.kt | 17 +------- .../boundary/dsl/model/DeploymentsContext.kt | 43 ++++++++++++++++++- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt index aefe1100ff..c23ae5adca 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt @@ -10,32 +10,17 @@ package it.unibo.alchemist.boundary.dsl import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.dsl.model.SimulationContext import it.unibo.alchemist.core.Engine import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.SupportedIncarnations -import org.apache.commons.math3.random.MersenneTwister abstract class DslLoader(private val ctx: SimulationContext) : Loader { @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation { - val incarnation = SupportedIncarnations.get(ctx.incarnation.name).get() - val randomGenerator = MersenneTwister(0) val environment = ctx.envCtx?.environment as Environment // Get deployments and add nodes - val deployments = ctx.envCtx?.ctxDeploy?.deployments ?: emptyList() - deployments.forEach { deployment -> - deployment.forEach { position -> - val node = incarnation.createNode( - randomGenerator, - environment, - null, - ) - environment.addNode(node, position as P) - } - } - return Engine(environment) } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index f7ecb62b02..b503de00dc 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -10,16 +10,55 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator class DeploymentsContext>(private val ctx: EnvironmentContext) { var deployments: MutableList> = mutableListOf() - var generator: RandomGenerator = MersenneTwister(0) + var generator: RandomGenerator = MersenneTwister(10) - fun deploy(deployment: Deployment<*>) { + fun deploy(deployment: Deployment<*>, block: ContentsContext.() -> Unit) { @Suppress("UNCHECKED_CAST") deployments.add(deployment as Deployment

) + addNodes(deployment) + ContentsContext().apply(block) + } + private fun addNodes(deployment: Deployment

) { + deployment.forEach { position -> + val node = ctx.incarnation.createNode( + generator, + ctx.environment, + null, + ) + ctx.environment.addNode(node, position) + } + } + + fun deploy(deployment: Deployment<*>) { + @Suppress("UNCHECKED_CAST") + this.deploy(deployment) {} + } + inner class ContentsContext { + fun all(block: ContentContext.() -> Unit) { + val c = ContentContext().apply(block) + ctx.environment.nodes.forEach { node -> + applyToNode(node, c) + } + } + private fun applyToNode(node: Node, content: ContentContext) { + val mol = ctx.incarnation.createMolecule( + content.molecule + ?: error("Molecule not specified"), + ) + val conc = ctx.incarnation.createConcentration(content.concentration) + node.setConcentration(mol, conc) + } + + inner class ContentContext { + var molecule: String? = null + var concentration: T? = null + } } } From fce686377c26f609d81064d5cd94fde9594ce01c Mon Sep 17 00:00:00 2001 From: marco Date: Fri, 5 Sep 2025 11:53:05 +0200 Subject: [PATCH 005/196] feat: handle linking rule --- .../alchemist/boundary/dsl/model/EnvironmentContext.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt index 165fa1f03d..c35b12fbc8 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.boundary.dsl.SimulationContext import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.LinkingRule @@ -19,7 +18,14 @@ import it.unibo.alchemist.model.linkingrules.NoLinks class EnvironmentContext>(private val ctx: SimulationContext, env: Environment) { val environment: Environment = env - var networkModel: LinkingRule = NoLinks() + private var _networkModel: LinkingRule = NoLinks() + var networkModel: LinkingRule + get() = _networkModel + set(value) { + _networkModel = value + environment.linkingRule = value + } + val ctxDeploy: DeploymentsContext = DeploymentsContext(this) val incarnation: Incarnation From 92e36424620dc80180eafaa1471a74c9127fbb30 Mon Sep 17 00:00:00 2001 From: marco Date: Fri, 5 Sep 2025 11:53:50 +0200 Subject: [PATCH 006/196] chore: change error message --- .../boundary/dsl/{ => model}/SimulationContext.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) rename alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/{ => model}/SimulationContext.kt (79%) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt similarity index 79% rename from alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt rename to alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index d41130a1f1..d1775d7812 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -1,10 +1,19 @@ -package it.unibo.alchemist.boundary.dsl +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.DependentVariable import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.model.EnvironmentContext +import it.unibo.alchemist.boundary.dsl.DslLoader import it.unibo.alchemist.boundary.dsl.model.Incarnation as Inc import it.unibo.alchemist.boundary.launchers.DefaultLauncher import it.unibo.alchemist.model.Environment @@ -25,7 +34,7 @@ class SimulationContext { } internal fun > getIncarnation(): Incarnation = SupportedIncarnations.get(incarnation.name).getOrElse { - throw IllegalArgumentException("Incarnation $incarnation not supported for the given types") + throw IllegalArgumentException("Incarnation $incarnation not supported") } } From c73e885fde6f614178564136ef90465664bd3c58 Mon Sep 17 00:00:00 2001 From: marco Date: Fri, 5 Sep 2025 11:55:36 +0200 Subject: [PATCH 007/196] test: improve testing add a helper function that allows to test if a loader generated by the dsl is the same as a loader generated by a yml file --- .../alchemist/dsl/LoaderComparisonHelper.kt | 191 ++++++++++++++++++ .../it/unibo/alchemist/dsl/TestComparison.kt | 120 +++++++++++ .../it/unibo/alchemist/dsl/TestContents.kt | 38 ++++ .../it/unibo/alchemist/dsl/TestDeployments.kt | 6 +- .../it/unibo/alchemist/dsl/TestSimulations.kt | 4 +- .../src/test/resources/dsl/01-nodes.yml | 11 + .../src/test/resources/dsl/02-manynodes.yml | 13 ++ .../src/test/resources/dsl/03-grid.yml | 9 + .../src/test/resources/dsl/05-content.yml | 11 + 9 files changed, 397 insertions(+), 6 deletions(-) create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt create mode 100644 alchemist-loading/src/test/resources/dsl/01-nodes.yml create mode 100644 alchemist-loading/src/test/resources/dsl/02-manynodes.yml create mode 100644 alchemist-loading/src/test/resources/dsl/03-grid.yml create mode 100644 alchemist-loading/src/test/resources/dsl/05-content.yml diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt new file mode 100644 index 0000000000..973ea8212d --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.boundary.LoadAlchemist +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.core.Simulation +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Position +import org.junit.jupiter.api.Assertions.assertEquals +import org.kaikikm.threadresloader.ResourceLoader + +/** + * Test helper for comparing DSL and YAML loaders + */ +object LoaderComparisonHelper { + + /** + * Compares a DSL loader with a YAML loader to ensure they produce equivalent simulations + */ + fun > compareLoaders(dslLoader: Loader, yamlResource: String) { + val yamlLoader = LoadAlchemist.from(ResourceLoader.getResource(yamlResource)!!) + + // Compare basic properties + compareBasicProperties(dslLoader, yamlLoader) + + // Compare simulations + compareSimulations(dslLoader, yamlLoader) + } + + /** + * Compares basic loader properties + */ + private fun compareBasicProperties(dslLoader: Loader, yamlLoader: Loader) { + println("Comparing basic properties...") + + // Compare constants + assertEquals( + yamlLoader.constants, + dslLoader.constants, + "Constants should match", + ) + + // Compare variables + assertEquals( + yamlLoader.variables, + dslLoader.variables, + "Variables should match", + ) + + // Compare dependent variables + assertEquals( + yamlLoader.dependentVariables, + dslLoader.dependentVariables, + "Dependent variables should match", + ) + + // Compare remote dependencies + assertEquals( + yamlLoader.remoteDependencies, + dslLoader.remoteDependencies, + "Remote dependencies should match", + ) + + // Compare launcher types (not exact instances) + assertEquals( + yamlLoader.launcher::class, + dslLoader.launcher::class, + "Launcher types should match", + ) + } + + /** + * Compares the simulations generated by both loaders + */ + private fun > compareSimulations(dslLoader: Loader, yamlLoader: Loader) { + println("Comparing simulations...") + + val dslSimulation = dslLoader.getDefault() + val yamlSimulation = yamlLoader.getDefault() + + // Compare environments + compareEnvironments(dslSimulation.environment, yamlSimulation.environment) + + // Compare simulation properties + compareSimulationProperties(dslSimulation, yamlSimulation) + } + + /** + * Compares two environments + */ + private fun > compareEnvironments(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing environments...") + + // Compare node counts + assertEquals( + yamlEnv.nodes.size, + dslEnv.nodes.size, + "Node counts should match", + ) + + // TODO: Commented out position comparison due to random generator differences + // Compare node positions + // val dslPositions = dslEnv.nodes.map { dslEnv.getPosition(it) }.toSet() + // val yamlPositions = yamlEnv.nodes.map { yamlEnv.getPosition(it) }.toSet() + // assertEquals( + // yamlPositions, + // dslPositions, + // "$description: Node positions should match" + // ) + + // Compare node contents (molecules and concentrations) + compareNodeContents(dslEnv, yamlEnv) + + // Compare linking rules + assertEquals( + yamlEnv.linkingRule::class, + dslEnv.linkingRule::class, + "Linking rule types should match", + ) + } + + /** + * Compares node contents (molecules and concentrations) + */ + private fun > compareNodeContents(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing node contents...") + + // Since we can't match by position, we'll compare all nodes by their contents + val dslNodes = dslEnv.nodes.toList() + val yamlNodes = yamlEnv.nodes.toList() + + // Compare total molecule counts + val dslTotalMolecules = dslNodes.sumOf { it.moleculeCount } + val yamlTotalMolecules = yamlNodes.sumOf { it.moleculeCount } + + assertEquals( + yamlTotalMolecules, + dslTotalMolecules, + "Total molecule counts should match", + ) + + // Compare all node contents (without position matching) + val dslContents = dslNodes.map { it.contents }.sortedBy { it.toString() } + val yamlContents = yamlNodes.map { it.contents }.sortedBy { it.toString() } + + assertEquals( + yamlContents, + dslContents, + "All node contents (molecules and concentrations) should match", + ) + } + + /** + * Compares simulation properties + */ + private fun compareSimulationProperties(dslSimulation: Simulation<*, *>, yamlSimulation: Simulation<*, *>) { + println("Comparing simulation properties...") + + // Compare output monitors count + assertEquals( + yamlSimulation.outputMonitors.size, + dslSimulation.outputMonitors.size, + "Output monitors count should match", + ) + + // Compare output monitor types by class since instances may differ + val yamlMonitorTypes = yamlSimulation.outputMonitors.map { it::class } + val dslMonitorTypes = dslSimulation.outputMonitors.map { it::class } + + assertEquals( + yamlMonitorTypes.sortedBy { it.simpleName }, + dslMonitorTypes.sortedBy { it.simpleName }, + "Output monitor types should match", + ) + } +} + +/** + * Extension function for easier test writing + */ +fun Loader.shouldEqual(yamlResource: String) { + @Suppress("UNCHECKED_CAST") + LoaderComparisonHelper.compareLoaders(this, yamlResource) +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt new file mode 100644 index 0000000000..3894eeb2ce --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.dsl + +import io.kotest.assertions.shouldFail +import it.unibo.alchemist.boundary.dsl.model.Incarnation +import it.unibo.alchemist.boundary.dsl.model.simulation +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.deployments.Circle +import it.unibo.alchemist.model.deployments.Grid +import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance +import org.apache.commons.math3.random.MersenneTwister +import org.junit.jupiter.api.Test + +class TestComparison { + + @Test + fun > test01Nodes() { + val loader = simulation { + incarnation = Incarnation.SAPERE + environment(getDefault()) { + networkModel = ConnectWithinDistance(5.0) + deployments { + deploy(Point(environment, 0.0, 0.0)) + deploy(Point(environment, 0.0, 1.0)) + } + } + } + + loader.shouldEqual("isac/01-nodes.yml") + } + + @Test + fun > test02ManyNodes() { + val loader = simulation { + incarnation = Incarnation.SAPERE + environment(getDefault()) { + networkModel = ConnectWithinDistance(5.0) + deployments { + generator = MersenneTwister(10) + val cirle = Circle( + environment, + generator, + 1000, + 0.0, + 0.0, + 10.0, + ) + deploy(cirle) + } + } + } + + loader.shouldEqual("dsl/02-manynodes.yml") + } + + @Test + fun > testShouldFail() { + val loader = simulation { + incarnation = Incarnation.SAPERE + environment(getDefault()) { + networkModel = ConnectWithinDistance(5.0) + deployments { + val grid = Grid( + environment, + generator, + -5.0, + -6.0, // different from the yml file + 5.0, + 5.0, + 0.25, + 0.25, + 0.0, + 0.0, + ) + deploy(grid) + } + } + } + shouldFail { + loader.shouldEqual("dsl/03-grid.yml") + } + } + + @Test + fun > test05Content() { + val loader = simulation { + incarnation = Incarnation.SAPERE + environment(getDefault()) { + networkModel = ConnectWithinDistance(5.0) + deployments { + val hello = "hello" + deploy( + Grid( + environment, generator, + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + all { + molecule = hello + } + } + } + } + } + loader.shouldEqual("dsl/05-content.yml") + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt new file mode 100644 index 0000000000..5f9ea7d1cc --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.boundary.dsl.model.Incarnation +import it.unibo.alchemist.boundary.dsl.model.simulation +import it.unibo.alchemist.model.deployments.Point +import org.junit.jupiter.api.Test + +class TestContents { + + @Test + fun testAll() { + val loader = simulation { + incarnation = Incarnation.SAPERE + environment(getDefault()) { + deployments { + val p = Point(environment, 0.0, 0.0) + deploy(p) { + all { + molecule = "test" + concentration = 1.0 + } + } + } + } + } + + loader.launch(loader.launcher) + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index 1323a08aaf..5055efa179 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -10,7 +10,7 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.model.Incarnation -import it.unibo.alchemist.boundary.dsl.simulation +import it.unibo.alchemist.boundary.dsl.model.simulation import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point import org.junit.jupiter.api.Test @@ -23,7 +23,8 @@ class TestDeployments { incarnation = Incarnation.SAPERE environment(getDefault()) { deployments { - Point(environment, 0.0, 0.0) + val p = Point(environment, 0.0, 0.0) + deploy(p) } } } @@ -67,7 +68,6 @@ class TestDeployments { } } } - loader.launch(loader.launcher) } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt index 3c49be10e4..936b33c7bf 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt @@ -10,7 +10,7 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.model.Incarnation -import it.unibo.alchemist.boundary.dsl.simulation +import it.unibo.alchemist.boundary.dsl.model.simulation import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import org.junit.jupiter.api.Test @@ -21,7 +21,6 @@ class TestSimulations { val loader = simulation { incarnation = Incarnation.SAPERE } - loader.launch(loader.launcher) } @@ -33,7 +32,6 @@ class TestSimulations { networkModel = ConnectWithinDistance(5.0) } } - loader.launch(loader.launcher) } } diff --git a/alchemist-loading/src/test/resources/dsl/01-nodes.yml b/alchemist-loading/src/test/resources/dsl/01-nodes.yml new file mode 100644 index 0000000000..b64b375972 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/01-nodes.yml @@ -0,0 +1,11 @@ +incarnation: sapere + +network-model: + type: ConnectWithinDistance + parameters: [5] + +deployments: + - type: Point + parameters: [0, 0] + - type: Point + parameters: [0, 1] diff --git a/alchemist-loading/src/test/resources/dsl/02-manynodes.yml b/alchemist-loading/src/test/resources/dsl/02-manynodes.yml new file mode 100644 index 0000000000..581fa8aed1 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/02-manynodes.yml @@ -0,0 +1,13 @@ +incarnation: sapere + +seeds: + scenario: 10.0 + simulation: 10.0 + +network-model: + type: ConnectWithinDistance + parameters: [0.5] + +deployments: + type: Circle + parameters: [1000, 0, 0, 10] diff --git a/alchemist-loading/src/test/resources/dsl/03-grid.yml b/alchemist-loading/src/test/resources/dsl/03-grid.yml new file mode 100644 index 0000000000..010565ebae --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/03-grid.yml @@ -0,0 +1,9 @@ +incarnation: sapere + +network-model: + type: ConnectWithinDistance + parameters: [0.5] + +deployments: + type: Grid + parameters: [-5, -5, 5, 5, 0.25, 0.25, 0, 0] \ No newline at end of file diff --git a/alchemist-loading/src/test/resources/dsl/05-content.yml b/alchemist-loading/src/test/resources/dsl/05-content.yml new file mode 100644 index 0000000000..d065057d75 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/05-content.yml @@ -0,0 +1,11 @@ +incarnation: sapere + +network-model: + type: ConnectWithinDistance + parameters: [0.5] + +deployments: + type: Grid + parameters: [-5, -5, 5, 5, 0.25, 0.25, 0.1, 0.1] + contents: + molecule: hello From 72f404eadf2f8f1a2f682537ce77a9e3ba2341ea Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 10 Sep 2025 16:43:50 +0200 Subject: [PATCH 008/196] feat!: add support for actions and conditions --- .../unibo/alchemist/boundary/dsl/DslLoader.kt | 4 +- .../boundary/dsl/model/DeploymentsContext.kt | 145 ++++++++++++++--- .../boundary/dsl/model/EnvironmentContext.kt | 37 ----- .../boundary/dsl/model/SimulationContext.kt | 66 ++++++-- .../alchemist/dsl/LoaderComparisonHelper.kt | 151 +++++++++++++++++- 5 files changed, 318 insertions(+), 85 deletions(-) delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt index c23ae5adca..03e39ef12f 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt @@ -16,10 +16,10 @@ import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position -abstract class DslLoader(private val ctx: SimulationContext) : Loader { +abstract class DslLoader(private val ctx: SimulationContext<*>) : Loader { @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation { - val environment = ctx.envCtx?.environment as Environment + val environment = ctx.environment as Environment // Get deployments and add nodes return Engine(environment) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index b503de00dc..785937e606 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -9,56 +9,149 @@ package it.unibo.alchemist.boundary.dsl.model +import it.unibo.alchemist.model.Action +import it.unibo.alchemist.model.Condition import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.PositionBasedFilter +import it.unibo.alchemist.model.Reaction +import it.unibo.alchemist.model.TimeDistribution import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator -class DeploymentsContext>(private val ctx: EnvironmentContext) { - var deployments: MutableList> = mutableListOf() +class DeploymentsContext>(ctx: EnvironmentContext) { var generator: RandomGenerator = MersenneTwister(10) + val environment: Environment<*, *> = ctx.environment as Environment<*, *> + val env = ctx.environment + private val inc = ctx.incarnation - fun deploy(deployment: Deployment<*>, block: ContentsContext.() -> Unit) { + fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) { @Suppress("UNCHECKED_CAST") - deployments.add(deployment as Deployment

) - addNodes(deployment) - ContentsContext().apply(block) + addNodes(deployment as Deployment

) + DeploymentContext().apply(block) + } + fun deploy(deployment: Deployment<*>) { + @Suppress("UNCHECKED_CAST") + this.deploy(deployment) {} } private fun addNodes(deployment: Deployment

) { deployment.forEach { position -> - val node = ctx.incarnation.createNode( + val node = inc.createNode( generator, - ctx.environment, + env, null, ) - ctx.environment.addNode(node, position) + env.addNode(node, position) } } - fun deploy(deployment: Deployment<*>) { - @Suppress("UNCHECKED_CAST") - this.deploy(deployment) {} - } - inner class ContentsContext { - fun all(block: ContentContext.() -> Unit) { - val c = ContentContext().apply(block) - ctx.environment.nodes.forEach { node -> - applyToNode(node, c) - } + inner class DeploymentContext { + fun all(block: ContentContext.() -> Unit) { + val c = ContentContext().apply(block) + applyToNodes(env.nodes, c) } - private fun applyToNode(node: Node, content: ContentContext) { - val mol = ctx.incarnation.createMolecule( - content.molecule - ?: error("Molecule not specified"), + fun inside(filter: PositionBasedFilter<*>, block: ContentContext.() -> Unit) { + @Suppress("UNCHECKED_CAST") + val filter = filter as PositionBasedFilter

+ val c = ContentContext().apply(block) + applyToNodes( + env.nodes.filter { node -> + filter.contains(env.getPosition(node)) + }, + c, ) - val conc = ctx.incarnation.createConcentration(content.concentration) - node.setConcentration(mol, conc) + } + fun programs(block: ProgramsContext.() -> Unit) { + ProgramsContext().apply(block) + } + private fun applyToNodes(nodes: Collection>, content: ContentContext) { + nodes.forEach { node -> + val mol = inc.createMolecule( + content.molecule + ?: error("Molecule not specified"), + ) + val conc = inc.createConcentration(content.concentration) + node.setConcentration(mol, conc) + } } - inner class ContentContext { + inner class ContentContext { var molecule: String? = null var concentration: T? = null } + inner class ProgramsContext { + val programs: MutableList Unit> = mutableListOf() + fun all(block: ProgramContext.() -> Unit) { + programs.add(block) + applyToNodes(env.nodes, block) + } + fun inside(filter: PositionBasedFilter

, block: ProgramContext.() -> Unit) { + programs.add(block) + applyToNodes( + env.nodes.filter { node -> + filter.contains(env.getPosition(node)) + }, + block, + ) + } + + private fun applyToNodes(nodes: Collection>, program: ProgramContext.() -> Unit) { + nodes.forEach { node -> + val c = ProgramContext(node).apply(program) + val timeDistribution = c.timeDistribution + ?: inc.createTimeDistribution( + generator, + env, + node, + null, + ) + val r = when { + c.reaction != null -> { + // User provided a custom reaction object + c.reaction!! + } + else -> { + // Create a basic reaction with custom actions/conditions + inc.createReaction( + generator, + env, + node, + timeDistribution, + c.program, + ) + } + } + r.actions = r.actions + c.actions.map { it() } + r.conditions = r.conditions + c.conditions.map { it() } + node.addReaction(r) + } + } + inner class ProgramContext(val node: Node) { + var program: String? = null + var actions: Collection<() -> Action> = emptyList() + var conditions: Collection<() -> Condition> = emptyList() + var timeDistribution: TimeDistribution? = null + var reaction: Reaction? = null + fun timeDistribution(td: String) { + timeDistribution = inc.createTimeDistribution( + generator, + env, + node, + td, + ) + } + fun addAction(block: () -> Action) { + actions = actions + block + } + fun addCondition(block: () -> Condition) { + conditions = conditions + block + } + + @Suppress("UNCHECKED_CAST") + operator fun TimeDistribution<*>.unaryPlus(): TimeDistribution = this as TimeDistribution + } + } } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt deleted file mode 100644 index c35b12fbc8..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/EnvironmentContext.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.LinkingRule -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.SupportedIncarnations -import it.unibo.alchemist.model.linkingrules.NoLinks - -class EnvironmentContext>(private val ctx: SimulationContext, env: Environment) { - val environment: Environment = env - private var _networkModel: LinkingRule = NoLinks() - var networkModel: LinkingRule - get() = _networkModel - set(value) { - _networkModel = value - environment.linkingRule = value - } - - val ctxDeploy: DeploymentsContext = DeploymentsContext(this) - - val incarnation: Incarnation - get() = SupportedIncarnations.get(ctx.incarnation.name).get() - - fun deployments(block: DeploymentsContext.() -> Unit) { - ctxDeploy.apply(block) - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index d1775d7812..6587924f4f 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -18,27 +18,58 @@ import it.unibo.alchemist.boundary.dsl.model.Incarnation as Inc import it.unibo.alchemist.boundary.launchers.DefaultLauncher import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.SupportedIncarnations import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.linkingrules.NoLinks import it.unibo.alchemist.model.positions.Euclidean2DPosition import kotlin.jvm.optionals.getOrElse -class SimulationContext { - var incarnation: Inc = Inc.SAPERE - var envCtx: EnvironmentContext<*, *>? = null +class SimulationContext { + var incarnation: Incarnation? = null + var environment: Environment? = null - fun getDefault(): Environment = Continuous2DEnvironment(this.getIncarnation()) - fun > environment(env: Environment, block: EnvironmentContext.() -> Unit) { - envCtx = EnvironmentContext(this, env).apply(block) + @Suppress("UNCHECKED_CAST") + val default: Environment by lazy { + require(incarnation != null) { + "Incarnation must be set before accessing default environment" + } + Continuous2DEnvironment(incarnation as Incarnation) + } + + fun > environment(env: Environment, block: EnvironmentContext.() -> Unit) { + this.environment = env + EnvironmentContext(this, env).apply(block) + } + fun environment(block: EnvironmentContext.() -> Unit) { + val env = default + this.environment = default + EnvironmentContext(this, env).apply(block) } - internal fun > getIncarnation(): Incarnation = - SupportedIncarnations.get(incarnation.name).getOrElse { - throw IllegalArgumentException("Incarnation $incarnation not supported") +} + +class EnvironmentContext>(val ctx: SimulationContext, val environment: Environment) { + + private var _networkModel: LinkingRule = NoLinks() + var networkModel: LinkingRule + get() = _networkModel + set(value) { + _networkModel = value + environment.linkingRule = value } + + @Suppress("UNCHECKED_CAST") + val incarnation: Incarnation + get() = ctx.incarnation as? Incarnation + ?: error("Incarnation not defined or of the wrong type") + + fun deployments(block: DeploymentsContext.() -> Unit) { + DeploymentsContext(this).apply(block) + } } -fun createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { +fun > createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { override val constants: Map = emptyMap() override val dependentVariables: Map> = emptyMap() override val variables: Map> = emptyMap() @@ -46,7 +77,18 @@ fun createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(sim override val launcher: Launcher = DefaultLauncher() } -fun simulation(block: SimulationContext.() -> Unit): Loader { - val sim = SimulationContext().apply(block) +fun > Inc.incarnation(): Incarnation = SupportedIncarnations.get(this.name).getOrElse { + throw IllegalArgumentException("Incarnation $this not supported") +} + +fun > simulation(incarnation: Incarnation, block: SimulationContext.() -> Unit): Loader { + val sim = SimulationContext().apply { + this.incarnation = incarnation + }.apply(block) + return createLoader(sim) +} + +fun simulation(block: SimulationContext.() -> Unit): Loader { + val sim = SimulationContext().apply(block) return createLoader(sim) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt index 973ea8212d..1abda85967 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt @@ -12,6 +12,7 @@ import it.unibo.alchemist.boundary.LoadAlchemist import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import org.junit.jupiter.api.Assertions.assertEquals import org.kaikikm.threadresloader.ResourceLoader @@ -105,15 +106,14 @@ object LoaderComparisonHelper { "Node counts should match", ) - // TODO: Commented out position comparison due to random generator differences // Compare node positions - // val dslPositions = dslEnv.nodes.map { dslEnv.getPosition(it) }.toSet() - // val yamlPositions = yamlEnv.nodes.map { yamlEnv.getPosition(it) }.toSet() - // assertEquals( - // yamlPositions, - // dslPositions, - // "$description: Node positions should match" - // ) + val dslPositions = dslEnv.nodes.map { dslEnv.getPosition(it) }.toSet() + val yamlPositions = yamlEnv.nodes.map { yamlEnv.getPosition(it) }.toSet() + assertEquals( + yamlPositions, + dslPositions, + "Node positions should match", + ) // Compare node contents (molecules and concentrations) compareNodeContents(dslEnv, yamlEnv) @@ -124,6 +124,9 @@ object LoaderComparisonHelper { dslEnv.linkingRule::class, "Linking rule types should match", ) + + // Compare programs (reactions) + comparePrograms(dslEnv, yamlEnv) } /** @@ -157,6 +160,138 @@ object LoaderComparisonHelper { ) } + /** + * Compares programs between environments + */ + private fun > comparePrograms(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing programs...") + + // Compare global reactions + compareGlobalReactions(dslEnv, yamlEnv) + + // Compare node reactions + compareNodeReactions(dslEnv, yamlEnv) + } + + /** + * Compares global reactions + */ + private fun > compareGlobalReactions(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing global reactions...") + + val dslGlobalReactions = dslEnv.globalReactions.toList() + val yamlGlobalReactions = yamlEnv.globalReactions.toList() + + assertEquals( + yamlGlobalReactions.size, + dslGlobalReactions.size, + "Global reactions count should match", + ) + + // Compare global reaction types + val dslGlobalTypes = dslGlobalReactions.map { it::class }.sortedBy { it.simpleName } + val yamlGlobalTypes = yamlGlobalReactions.map { it::class }.sortedBy { it.simpleName } + + assertEquals( + yamlGlobalTypes, + dslGlobalTypes, + "Global reaction types should match", + ) + } + + /** + * Compares node reactions (programs) + */ + private fun > compareNodeReactions(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing node reactions...") + + val dslNodes = dslEnv.nodes.toList() + val yamlNodes = yamlEnv.nodes.toList() + + // Compare total reaction counts + val dslTotalReactions = dslNodes.sumOf { it.reactions.size } + val yamlTotalReactions = yamlNodes.sumOf { it.reactions.size } + + assertEquals( + yamlTotalReactions, + dslTotalReactions, + "Total node reactions count should match", + ) + + // Compare reaction types across all nodes + val dslReactionTypes = dslNodes.flatMap { it.reactions }.map { it::class }.sortedBy { it.simpleName } + val yamlReactionTypes = yamlNodes.flatMap { it.reactions }.map { it::class }.sortedBy { it.simpleName } + + assertEquals( + yamlReactionTypes, + dslReactionTypes, + "Node reaction types should match", + ) + + // Compare reaction programs (conditions and actions) + compareReactionPrograms(dslNodes, yamlNodes) + } + + /** + * Compares reaction programs by comparing their string representations and dependencies + */ + private fun compareReactionPrograms(dslNodes: List>, yamlNodes: List>) { + println("Comparing reaction programs...") + + // Compare total reactions count + val dslTotalReactions = dslNodes.sumOf { it.reactions.size } + val yamlTotalReactions = yamlNodes.sumOf { it.reactions.size } + + assertEquals( + yamlTotalReactions, + dslTotalReactions, + "Total reactions count should match", + ) + + // Compare reactions by their string representations and dependencies + val dslReactions = dslNodes.flatMap { it.reactions }.map { reaction -> + ReactionInfo( + reactionString = try { + reaction.toString() + } catch (e: Exception) { + "" + }, + inboundDependencies = reaction.inboundDependencies.map { it.toString() }.sorted(), + outboundDependencies = reaction.outboundDependencies.map { it.toString() }.sorted(), + ) + }.sortedBy { it.toString() } + + val yamlReactions = yamlNodes.flatMap { it.reactions }.map { reaction -> + ReactionInfo( + reactionString = try { + reaction.toString() + } catch (e: Exception) { + "" + }, + inboundDependencies = reaction.inboundDependencies.map { it.toString() }.sorted(), + outboundDependencies = reaction.outboundDependencies.map { it.toString() }.sorted(), + ) + }.sortedBy { it.toString() } + + assertEquals( + yamlReactions, + dslReactions, + "Reaction string representations and dependencies should match", + ) + } + + /** + * Data class to represent reaction information for comparison + */ + private data class ReactionInfo( + val reactionString: String, + val inboundDependencies: List, + val outboundDependencies: List, + ) { + override fun toString(): String = + "Reaction(string='$reactionString', inbound=$inboundDependencies, outbound=$outboundDependencies)" + } + /** * Compares simulation properties */ From c1dd1a95429c6cd3878483883bf5122c10225483 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 10 Sep 2025 16:46:41 +0200 Subject: [PATCH 009/196] test: add tests for new features --- .../it/unibo/alchemist/dsl/TestComparison.kt | 119 +++++------------- .../it/unibo/alchemist/dsl/TestContents.kt | 10 +- .../it/unibo/alchemist/dsl/TestDeployments.kt | 20 +-- .../it/unibo/alchemist/dsl/TestSimulations.kt | 12 +- .../src/test/resources/dsl/06-filters.yml | 16 +++ .../src/test/resources/dsl/07-program.yml | 19 +++ .../test/resources/dsl/08-protelisprogram.yml | 25 ++++ .../resources/dsl/09-timedistribution.yml | 23 ++++ .../src/test/resources/dsl/10-environment.yml | 25 ++++ 9 files changed, 162 insertions(+), 107 deletions(-) create mode 100644 alchemist-loading/src/test/resources/dsl/06-filters.yml create mode 100644 alchemist-loading/src/test/resources/dsl/07-program.yml create mode 100644 alchemist-loading/src/test/resources/dsl/08-protelisprogram.yml create mode 100644 alchemist-loading/src/test/resources/dsl/09-timedistribution.yml create mode 100755 alchemist-loading/src/test/resources/dsl/10-environment.yml diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt index 3894eeb2ce..07146c8063 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt @@ -9,112 +9,53 @@ package it.unibo.alchemist.dsl -import io.kotest.assertions.shouldFail -import it.unibo.alchemist.boundary.dsl.model.Incarnation -import it.unibo.alchemist.boundary.dsl.model.simulation import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.deployments.Circle -import it.unibo.alchemist.model.deployments.Grid -import it.unibo.alchemist.model.deployments.Point -import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance -import org.apache.commons.math3.random.MersenneTwister import org.junit.jupiter.api.Test class TestComparison { @Test fun > test01Nodes() { - val loader = simulation { - incarnation = Incarnation.SAPERE - environment(getDefault()) { - networkModel = ConnectWithinDistance(5.0) - deployments { - deploy(Point(environment, 0.0, 0.0)) - deploy(Point(environment, 0.0, 1.0)) - } - } - } - - loader.shouldEqual("isac/01-nodes.yml") + DslLoaderFunctions.test01Nodes().shouldEqual("dsl/01-nodes.yml") } @Test fun > test02ManyNodes() { - val loader = simulation { - incarnation = Incarnation.SAPERE - environment(getDefault()) { - networkModel = ConnectWithinDistance(5.0) - deployments { - generator = MersenneTwister(10) - val cirle = Circle( - environment, - generator, - 1000, - 0.0, - 0.0, - 10.0, - ) - deploy(cirle) - } - } - } - - loader.shouldEqual("dsl/02-manynodes.yml") + DslLoaderFunctions.test02ManyNodes().shouldEqual("dsl/02-manynodes.yml") } @Test - fun > testShouldFail() { - val loader = simulation { - incarnation = Incarnation.SAPERE - environment(getDefault()) { - networkModel = ConnectWithinDistance(5.0) - deployments { - val grid = Grid( - environment, - generator, - -5.0, - -6.0, // different from the yml file - 5.0, - 5.0, - 0.25, - 0.25, - 0.0, - 0.0, - ) - deploy(grid) - } - } - } - shouldFail { - loader.shouldEqual("dsl/03-grid.yml") - } + fun > test03Grid() { + DslLoaderFunctions.test03Grid().shouldEqual("dsl/03-grid.yml") } @Test fun > test05Content() { - val loader = simulation { - incarnation = Incarnation.SAPERE - environment(getDefault()) { - networkModel = ConnectWithinDistance(5.0) - deployments { - val hello = "hello" - deploy( - Grid( - environment, generator, - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, 0.25, 0.1, 0.1, - ), - ) { - all { - molecule = hello - } - } - } - } - } - loader.shouldEqual("dsl/05-content.yml") + DslLoaderFunctions.test05Content().shouldEqual("dsl/05-content.yml") + } + + @Test + fun > test06ContentFiltered() { + DslLoaderFunctions.test06ContentFiltered().shouldEqual("dsl/06-filters.yml") + } + + @Test + fun > test07Programs() { + DslLoaderFunctions.test07Programs().shouldEqual("dsl/07-program.yml") + } + + @Test + fun > test08ProtelisPrograms() { + DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/08-protelisprogram.yml") + } + + @Test + fun > test09TimeDistribution() { + DslLoaderFunctions.test09TimeDistribution().shouldEqual("dsl/09-timedistribution.yml") + } + + @Test + fun > test10Environment() { + DslLoaderFunctions.test10Environment().shouldEqual("dsl/10-environment.yml") } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt index 5f9ea7d1cc..3e6fc860d6 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -9,18 +9,20 @@ package it.unibo.alchemist.dsl -import it.unibo.alchemist.boundary.dsl.model.Incarnation +import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE +import it.unibo.alchemist.boundary.dsl.model.incarnation import it.unibo.alchemist.boundary.dsl.model.simulation import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.positions.Euclidean2DPosition import org.junit.jupiter.api.Test class TestContents { @Test fun testAll() { - val loader = simulation { - incarnation = Incarnation.SAPERE - environment(getDefault()) { + val incarnation = SAPERE.incarnation() + val loader = simulation(incarnation) { + environment { deployments { val p = Point(environment, 0.0, 0.0) deploy(p) { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index 5055efa179..eca3d27c03 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -10,18 +10,20 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.model.Incarnation +import it.unibo.alchemist.boundary.dsl.model.incarnation import it.unibo.alchemist.boundary.dsl.model.simulation import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.positions.Euclidean2DPosition import org.junit.jupiter.api.Test class TestDeployments { @Test fun testDeployments() { - val loader = simulation { - incarnation = Incarnation.SAPERE - environment(getDefault()) { + val incarnation = Incarnation.SAPERE.incarnation() + val loader = simulation(incarnation) { + environment { deployments { val p = Point(environment, 0.0, 0.0) deploy(p) @@ -34,9 +36,9 @@ class TestDeployments { @Test fun testMultipleDeployments() { - val loader = simulation { - incarnation = Incarnation.SAPERE - environment(getDefault()) { + val incarnation = Incarnation.SAPERE.incarnation() + val loader = simulation(incarnation) { + environment { deployments { val point = Point(environment, 0.0, 0.0) deploy(point) @@ -50,9 +52,9 @@ class TestDeployments { @Test fun testGridDeployment() { - val loader = simulation { - incarnation = Incarnation.SAPERE - environment(getDefault()) { + val incarnation = Incarnation.SAPERE.incarnation() + val loader = simulation(incarnation) { + environment { deployments { val grid = Grid( environment, diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt index 936b33c7bf..a0916d7375 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt @@ -10,25 +10,27 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.model.Incarnation +import it.unibo.alchemist.boundary.dsl.model.incarnation import it.unibo.alchemist.boundary.dsl.model.simulation import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance +import it.unibo.alchemist.model.positions.Euclidean2DPosition import org.junit.jupiter.api.Test class TestSimulations { @Test fun testIncarnation() { - val loader = simulation { - incarnation = Incarnation.SAPERE + val incarnation = Incarnation.SAPERE.incarnation() + val loader = simulation(incarnation) { } loader.launch(loader.launcher) } @Test fun testLinkingRule() { - val loader = simulation { - incarnation = Incarnation.SAPERE - environment(getDefault()) { + val incarnation = Incarnation.SAPERE.incarnation() + val loader = simulation(incarnation) { + environment { networkModel = ConnectWithinDistance(5.0) } } diff --git a/alchemist-loading/src/test/resources/dsl/06-filters.yml b/alchemist-loading/src/test/resources/dsl/06-filters.yml new file mode 100644 index 0000000000..dedebd5496 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/06-filters.yml @@ -0,0 +1,16 @@ +incarnation: sapere + +network-model: + type: ConnectWithinDistance + parameters: [0.5] + +deployments: + type: Grid + parameters: [-5, -5, 5, 5, 0.25, 0.25, 0.1, 0.1] + contents: + - molecule: hello + - in: + type: Rectangle + parameters: [-1, -1, 2, 2] + + molecule: token diff --git a/alchemist-loading/src/test/resources/dsl/07-program.yml b/alchemist-loading/src/test/resources/dsl/07-program.yml new file mode 100644 index 0000000000..c8f7425be8 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/07-program.yml @@ -0,0 +1,19 @@ +incarnation: sapere + +network-model: + type: ConnectWithinDistance + parameters: [0.5] + +deployments: + type: Grid + parameters: [-5, -5, 5, 5, 0.25, 0.25, 0.1, 0.1] + contents: + in: + type: Rectangle + parameters: [-0.5, -0.5, 1, 1] + molecule: token + programs: + - time-distribution: 1 + program: > + {token} --> {firing} + - program: "{firing} --> +{token}" diff --git a/alchemist-loading/src/test/resources/dsl/08-protelisprogram.yml b/alchemist-loading/src/test/resources/dsl/08-protelisprogram.yml new file mode 100644 index 0000000000..58186119d1 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/08-protelisprogram.yml @@ -0,0 +1,25 @@ +incarnation: protelis + +deployments: + - type: Point + parameters: [ 1.5, 0.5 ] + programs: + - time-distribution: + type: JaktaTimeDistribution + # Recursive construction of other types + parameters: + sense: + type: WeibullTime + parameters: [1.0, 1.0] + deliberate: + type: DiracComb + parameters: 0.1 + act: + type: ExponentialTime + parameters: 1.0 + program: | + 1 + 1 + +#terminate: +# - type: AfterTime +# parameters: [ 0 ] diff --git a/alchemist-loading/src/test/resources/dsl/09-timedistribution.yml b/alchemist-loading/src/test/resources/dsl/09-timedistribution.yml new file mode 100644 index 0000000000..e7a83147e8 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/09-timedistribution.yml @@ -0,0 +1,23 @@ +incarnation: sapere + +network-model: + type: ConnectWithinDistance + parameters: [0.5] + +_send: &grad + - time-distribution: + type: DiracComb + parameters: [0.5] + program: "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" + - program: > + {token, N, L}{token, def: N2>=N, L2} --> {token, N, L} + +deployments: + type: Grid + parameters: [-5, -5, 5, 5, 0.25, 0.25, 0.1, 0.1] + contents: + in: + type: Rectangle + parameters: [-0.5, -0.5, 1, 1] + molecule: token, 0, [] + programs: *grad \ No newline at end of file diff --git a/alchemist-loading/src/test/resources/dsl/10-environment.yml b/alchemist-loading/src/test/resources/dsl/10-environment.yml new file mode 100755 index 0000000000..1f3644fa0e --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/10-environment.yml @@ -0,0 +1,25 @@ +environment: + type: OSMEnvironment + parameters: ["vcm.pbf", false] # Requires the file vcm.pbf in the classpath! + +incarnation: sapere + +_pools: + - pool: &move + - time-distribution: 0.1 + type: Event + actions: + - type: ReproduceGPSTrace + parameters: ["gpsTrace", true, "AlignToSimulationTime"] + +deployments: + - type: FromGPSTrace + parameters: [7, "gpsTrace", true, "AlignToSimulationTime"] + programs: + - *move + +terminate: + type: StableForSteps + parameters: + equalIntervals: 5 + checkInterval: 100 From 2e10f24d7e8a8596cec84183ed51995501275f4d Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 10 Sep 2025 19:52:54 +0200 Subject: [PATCH 010/196] feat: add support for terminators --- .../boundary/dsl/model/SimulationContext.kt | 5 + .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 271 ++++++++++++++++++ .../alchemist/dsl/LoaderComparisonHelper.kt | 2 + 3 files changed, 278 insertions(+) create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 6587924f4f..2dfd51c015 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -21,6 +21,7 @@ import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.SupportedIncarnations +import it.unibo.alchemist.model.TerminationPredicate import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.linkingrules.NoLinks import it.unibo.alchemist.model.positions.Euclidean2DPosition @@ -67,6 +68,10 @@ class EnvironmentContext>(val ctx: SimulationContext, val fun deployments(block: DeploymentsContext.() -> Unit) { DeploymentsContext(this).apply(block) } + infix fun addTerminator(predicate: TerminationPredicate<*, *>) { + @Suppress("UNCHECKED_CAST") + environment.addTerminator(predicate as TerminationPredicate) + } } fun > createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt new file mode 100644 index 0000000000..7376e661eb --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.dsl.model.Incarnation.PROTELIS +import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE +import it.unibo.alchemist.boundary.dsl.model.incarnation +import it.unibo.alchemist.boundary.dsl.model.simulation +import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution +import it.unibo.alchemist.model.GeoPosition +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.deployments.Circle +import it.unibo.alchemist.model.deployments.Grid +import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance +import it.unibo.alchemist.model.maps.actions.ReproduceGPSTrace +import it.unibo.alchemist.model.maps.deployments.FromGPSTrace +import it.unibo.alchemist.model.maps.environments.OSMEnvironment +import it.unibo.alchemist.model.positionfilters.Rectangle +import it.unibo.alchemist.model.reactions.Event +import it.unibo.alchemist.model.terminators.StableForSteps +import it.unibo.alchemist.model.timedistributions.DiracComb +import it.unibo.alchemist.model.timedistributions.ExponentialTime +import it.unibo.alchemist.model.timedistributions.WeibullTime +import org.apache.commons.math3.random.MersenneTwister + +object DslLoaderFunctions { + fun > test01Nodes(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + environment { + networkModel = ConnectWithinDistance(5.0) + deployments { + deploy(Point(environment, 0.0, 0.0)) + deploy(Point(environment, 0.0, 1.0)) + } + } + } + } + + fun > test02ManyNodes(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + environment { + networkModel = ConnectWithinDistance(5.0) + deployments { + generator = MersenneTwister(10) + val circle = Circle( + environment, + generator, + 1000, + 0.0, + 0.0, + 10.0, + ) + deploy(circle) + } + } + } + } + + fun > test03Grid(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + environment { + networkModel = ConnectWithinDistance(5.0) + deployments { + val grid = Grid( + environment, + generator, + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.25, + 0.0, + 0.0, + ) + deploy(grid) + } + } + } + } + + fun > test05Content(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + environment { + networkModel = ConnectWithinDistance(5.0) + deployments { + val hello = "hello" + deploy( + Grid( + environment, generator, + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + all { + molecule = hello + } + } + } + } + } + } + + fun > test06ContentFiltered(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + environment { + networkModel = ConnectWithinDistance(5.0) + deployments { + val hello = "hello" + deploy( + Grid( + environment, generator, + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + all { + molecule = hello + } + inside(Rectangle(-1.0, -1.0, 2.0, 2.0)) { + molecule = "token" + } + } + } + } + } + } + + fun > test07Programs(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + environment { + networkModel = ConnectWithinDistance(5.0) + deployments { + val token = "token" + deploy( + Grid( + environment, generator, + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { + molecule = token + } + programs { + all { + timeDistribution("1") + program = "{token} --> {firing}" + } + all { + program = "{firing} --> +{token}" + } + } + } + } + } + } + } + + fun > test08ProtelisPrograms(): Loader { + val incarnation = PROTELIS.incarnation() + return simulation(incarnation) { + environment { + deployments { + deploy(Point(environment, 1.5, 0.5)) { + programs { + all { + timeDistribution = +JaktaTimeDistribution( + sense = WeibullTime(1.0, 1.0, generator), + deliberate = DiracComb(0.1), + act = ExponentialTime(1.0, generator), + ) + program = "1 + 1" + } + } + } + } + } + } + } + + fun > test09TimeDistribution(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + environment(default) { + networkModel = ConnectWithinDistance(5.0) + deployments { + deploy( + Grid( + environment, generator, + -5.0, -5.0, 5.0, 5.0, 0.25, 0.25, 0.1, 0.1, + ), + ) { + inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { + molecule = "token, 0, []" + programs { + all { + timeDistribution = DiracComb(0.5) + program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" + } + all { + program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" + } + } + } + } + } + } + } + } + + fun > test10Environment(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + val env = OSMEnvironment(incarnation, "vcm.pbf", false) + environment(env) { + addTerminator(StableForSteps(5, 100)) + deployments { + val gps = FromGPSTrace( + 7, + "gpsTrace", + true, + "AlignToSimulationTime", + ) + deploy(gps) { + programs { + all { + timeDistribution("0.1") + reaction = Event(node, timeDistribution) + addAction { + ReproduceGPSTrace( + env, + node, + reaction, + "gpsTrace", + true, + "AlignToSimulationTime", + ) + } + } + } + } + } + } + } + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt index 1abda85967..1cd999b96e 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt @@ -314,6 +314,8 @@ object LoaderComparisonHelper { dslMonitorTypes.sortedBy { it.simpleName }, "Output monitor types should match", ) + + // How to compare terminators...? } } From 92fdfefd198d2862dbdcf7a5126286366c87608b Mon Sep 17 00:00:00 2001 From: marco Date: Thu, 11 Sep 2025 11:27:09 +0200 Subject: [PATCH 011/196] refactor: simplify dsl syntax --- .../unibo/alchemist/boundary/dsl/DslLoader.kt | 2 +- .../boundary/dsl/model/DeploymentsContext.kt | 2 +- .../boundary/dsl/model/SimulationContext.kt | 51 +-- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 292 ++++++++---------- .../it/unibo/alchemist/dsl/TestContents.kt | 13 +- .../it/unibo/alchemist/dsl/TestDeployments.kt | 44 ++- .../it/unibo/alchemist/dsl/TestSimulations.kt | 4 +- 7 files changed, 179 insertions(+), 229 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt index 03e39ef12f..317d58a9fb 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt @@ -16,7 +16,7 @@ import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position -abstract class DslLoader(private val ctx: SimulationContext<*>) : Loader { +abstract class DslLoader(private val ctx: SimulationContext<*, *>) : Loader { @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation { val environment = ctx.environment as Environment diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index 785937e606..61ba9df645 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -21,7 +21,7 @@ import it.unibo.alchemist.model.TimeDistribution import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator -class DeploymentsContext>(ctx: EnvironmentContext) { +class DeploymentsContext>(ctx: SimulationContext) { var generator: RandomGenerator = MersenneTwister(10) val environment: Environment<*, *> = ctx.environment as Environment<*, *> val env = ctx.environment diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 2dfd51c015..f63b29eaae 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -27,30 +27,7 @@ import it.unibo.alchemist.model.linkingrules.NoLinks import it.unibo.alchemist.model.positions.Euclidean2DPosition import kotlin.jvm.optionals.getOrElse -class SimulationContext { - var incarnation: Incarnation? = null - var environment: Environment? = null - - @Suppress("UNCHECKED_CAST") - val default: Environment by lazy { - require(incarnation != null) { - "Incarnation must be set before accessing default environment" - } - Continuous2DEnvironment(incarnation as Incarnation) - } - - fun > environment(env: Environment, block: EnvironmentContext.() -> Unit) { - this.environment = env - EnvironmentContext(this, env).apply(block) - } - fun environment(block: EnvironmentContext.() -> Unit) { - val env = default - this.environment = default - EnvironmentContext(this, env).apply(block) - } -} - -class EnvironmentContext>(val ctx: SimulationContext, val environment: Environment) { +class SimulationContext>(val incarnation: Incarnation, val environment: Environment) { private var _networkModel: LinkingRule = NoLinks() var networkModel: LinkingRule @@ -60,11 +37,6 @@ class EnvironmentContext>(val ctx: SimulationContext, val environment.linkingRule = value } - @Suppress("UNCHECKED_CAST") - val incarnation: Incarnation - get() = ctx.incarnation as? Incarnation - ?: error("Incarnation not defined or of the wrong type") - fun deployments(block: DeploymentsContext.() -> Unit) { DeploymentsContext(this).apply(block) } @@ -74,7 +46,7 @@ class EnvironmentContext>(val ctx: SimulationContext, val } } -fun > createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { +fun > createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { override val constants: Map = emptyMap() override val dependentVariables: Map> = emptyMap() override val variables: Map> = emptyMap() @@ -86,14 +58,21 @@ fun > Inc.incarnation(): Incarnation = SupportedIncarna throw IllegalArgumentException("Incarnation $this not supported") } -fun > simulation(incarnation: Incarnation, block: SimulationContext.() -> Unit): Loader { - val sim = SimulationContext().apply { - this.incarnation = incarnation - }.apply(block) +fun > simulation( + incarnation: Incarnation, + environment: Environment, + block: SimulationContext.() -> Unit, +): Loader { + val sim = SimulationContext(incarnation, environment).apply(block) return createLoader(sim) } -fun simulation(block: SimulationContext.() -> Unit): Loader { - val sim = SimulationContext().apply(block) +fun > simulation( + incarnation: Incarnation, + block: SimulationContext.() -> Unit, +): Loader { + @Suppress("UNCHECKED_CAST") + val defaultEnv = Continuous2DEnvironment(incarnation as Incarnation) + val sim = SimulationContext(incarnation, defaultEnv).apply(block) return createLoader(sim) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 7376e661eb..54ef798548 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -36,12 +36,10 @@ object DslLoaderFunctions { fun > test01Nodes(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - environment { - networkModel = ConnectWithinDistance(5.0) - deployments { - deploy(Point(environment, 0.0, 0.0)) - deploy(Point(environment, 0.0, 1.0)) - } + networkModel = ConnectWithinDistance(5.0) + deployments { + deploy(Point(environment, 0.0, 0.0)) + deploy(Point(environment, 0.0, 1.0)) } } } @@ -49,20 +47,18 @@ object DslLoaderFunctions { fun > test02ManyNodes(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - environment { - networkModel = ConnectWithinDistance(5.0) - deployments { - generator = MersenneTwister(10) - val circle = Circle( - environment, - generator, - 1000, - 0.0, - 0.0, - 10.0, - ) - deploy(circle) - } + networkModel = ConnectWithinDistance(5.0) + deployments { + generator = MersenneTwister(10) + val circle = Circle( + environment, + generator, + 1000, + 0.0, + 0.0, + 10.0, + ) + deploy(circle) } } } @@ -70,23 +66,21 @@ object DslLoaderFunctions { fun > test03Grid(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - environment { - networkModel = ConnectWithinDistance(5.0) - deployments { - val grid = Grid( - environment, - generator, - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, - 0.25, - 0.0, - 0.0, - ) - deploy(grid) - } + networkModel = ConnectWithinDistance(5.0) + deployments { + val grid = Grid( + environment, + generator, + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.25, + 0.0, + 0.0, + ) + deploy(grid) } } } @@ -94,23 +88,21 @@ object DslLoaderFunctions { fun > test05Content(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - environment { - networkModel = ConnectWithinDistance(5.0) - deployments { - val hello = "hello" - deploy( - Grid( - environment, generator, - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, 0.25, 0.1, 0.1, - ), - ) { - all { - molecule = hello - } + networkModel = ConnectWithinDistance(5.0) + deployments { + val hello = "hello" + deploy( + Grid( + environment, generator, + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + all { + molecule = hello } } } @@ -120,26 +112,24 @@ object DslLoaderFunctions { fun > test06ContentFiltered(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - environment { - networkModel = ConnectWithinDistance(5.0) - deployments { - val hello = "hello" - deploy( - Grid( - environment, generator, - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, 0.25, 0.1, 0.1, - ), - ) { - all { - molecule = hello - } - inside(Rectangle(-1.0, -1.0, 2.0, 2.0)) { - molecule = "token" - } + networkModel = ConnectWithinDistance(5.0) + deployments { + val hello = "hello" + deploy( + Grid( + environment, generator, + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + all { + molecule = hello + } + inside(Rectangle(-1.0, -1.0, 2.0, 2.0)) { + molecule = "token" } } } @@ -149,31 +139,29 @@ object DslLoaderFunctions { fun > test07Programs(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - environment { - networkModel = ConnectWithinDistance(5.0) - deployments { - val token = "token" - deploy( - Grid( - environment, generator, - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, 0.25, 0.1, 0.1, - ), - ) { - inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { - molecule = token + networkModel = ConnectWithinDistance(5.0) + deployments { + val token = "token" + deploy( + Grid( + environment, generator, + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { + molecule = token + } + programs { + all { + timeDistribution("1") + program = "{token} --> {firing}" } - programs { - all { - timeDistribution("1") - program = "{token} --> {firing}" - } - all { - program = "{firing} --> +{token}" - } + all { + program = "{firing} --> +{token}" } } } @@ -184,18 +172,16 @@ object DslLoaderFunctions { fun > test08ProtelisPrograms(): Loader { val incarnation = PROTELIS.incarnation() return simulation(incarnation) { - environment { - deployments { - deploy(Point(environment, 1.5, 0.5)) { - programs { - all { - timeDistribution = +JaktaTimeDistribution( - sense = WeibullTime(1.0, 1.0, generator), - deliberate = DiracComb(0.1), - act = ExponentialTime(1.0, generator), - ) - program = "1 + 1" - } + deployments { + deploy(Point(environment, 1.5, 0.5)) { + programs { + all { + timeDistribution = +JaktaTimeDistribution( + sense = WeibullTime(1.0, 1.0, generator), + deliberate = DiracComb(0.1), + act = ExponentialTime(1.0, generator), + ) + program = "1 + 1" } } } @@ -206,25 +192,23 @@ object DslLoaderFunctions { fun > test09TimeDistribution(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - environment(default) { - networkModel = ConnectWithinDistance(5.0) - deployments { - deploy( - Grid( - environment, generator, - -5.0, -5.0, 5.0, 5.0, 0.25, 0.25, 0.1, 0.1, - ), - ) { - inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { - molecule = "token, 0, []" - programs { - all { - timeDistribution = DiracComb(0.5) - program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" - } - all { - program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" - } + networkModel = ConnectWithinDistance(5.0) + deployments { + deploy( + Grid( + environment, generator, + -5.0, -5.0, 5.0, 5.0, 0.25, 0.25, 0.1, 0.1, + ), + ) { + inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { + molecule = "token, 0, []" + programs { + all { + timeDistribution = DiracComb(0.5) + program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" + } + all { + program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" } } } @@ -235,32 +219,30 @@ object DslLoaderFunctions { fun > test10Environment(): Loader { val incarnation = SAPERE.incarnation() - return simulation(incarnation) { - val env = OSMEnvironment(incarnation, "vcm.pbf", false) - environment(env) { - addTerminator(StableForSteps(5, 100)) - deployments { - val gps = FromGPSTrace( - 7, - "gpsTrace", - true, - "AlignToSimulationTime", - ) - deploy(gps) { - programs { - all { - timeDistribution("0.1") - reaction = Event(node, timeDistribution) - addAction { - ReproduceGPSTrace( - env, - node, - reaction, - "gpsTrace", - true, - "AlignToSimulationTime", - ) - } + val env = OSMEnvironment(incarnation, "vcm.pbf", false) + return simulation(incarnation, env) { + addTerminator(StableForSteps(5, 100)) + deployments { + val gps = FromGPSTrace( + 7, + "gpsTrace", + true, + "AlignToSimulationTime", + ) + deploy(gps) { + programs { + all { + timeDistribution("0.1") + reaction = Event(node, timeDistribution) + addAction { + ReproduceGPSTrace( + env, + node, + reaction, + "gpsTrace", + true, + "AlignToSimulationTime", + ) } } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt index 3e6fc860d6..d548ceab68 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -22,14 +22,11 @@ class TestContents { fun testAll() { val incarnation = SAPERE.incarnation() val loader = simulation(incarnation) { - environment { - deployments { - val p = Point(environment, 0.0, 0.0) - deploy(p) { - all { - molecule = "test" - concentration = 1.0 - } + deployments { + deploy(Point(environment, 0.0, 0.0)) { + all { + molecule = "test" + concentration = 1.0 } } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index eca3d27c03..75ed80e2f0 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -23,11 +23,9 @@ class TestDeployments { fun testDeployments() { val incarnation = Incarnation.SAPERE.incarnation() val loader = simulation(incarnation) { - environment { - deployments { - val p = Point(environment, 0.0, 0.0) - deploy(p) - } + deployments { + val p = Point(environment, 0.0, 0.0) + deploy(p) } } @@ -38,12 +36,10 @@ class TestDeployments { fun testMultipleDeployments() { val incarnation = Incarnation.SAPERE.incarnation() val loader = simulation(incarnation) { - environment { - deployments { - val point = Point(environment, 0.0, 0.0) - deploy(point) - deploy(Point(environment, 1.0, 1.0)) - } + deployments { + val point = Point(environment, 0.0, 0.0) + deploy(point) + deploy(Point(environment, 1.0, 1.0)) } } @@ -54,20 +50,18 @@ class TestDeployments { fun testGridDeployment() { val incarnation = Incarnation.SAPERE.incarnation() val loader = simulation(incarnation) { - environment { - deployments { - val grid = Grid( - environment, - generator, - 1.0, - 1.0, - 5.0, - 5.0, - 1.0, - 1.0, - ) - deploy(grid) - } + deployments { + val grid = Grid( + environment, + generator, + 1.0, + 1.0, + 5.0, + 5.0, + 1.0, + 1.0, + ) + deploy(grid) } } loader.launch(loader.launcher) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt index a0916d7375..0be07fa348 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt @@ -30,9 +30,7 @@ class TestSimulations { fun testLinkingRule() { val incarnation = Incarnation.SAPERE.incarnation() val loader = simulation(incarnation) { - environment { - networkModel = ConnectWithinDistance(5.0) - } + networkModel = ConnectWithinDistance(5.0) } loader.launch(loader.launcher) } From 4b99ab38b0e29d44bdd627a0a20112b2277a4143 Mon Sep 17 00:00:00 2001 From: marco Date: Thu, 11 Sep 2025 12:01:23 +0200 Subject: [PATCH 012/196] feat: add support for output monitors --- .../it/unibo/alchemist/boundary/dsl/DslLoader.kt | 8 ++++++-- .../alchemist/boundary/dsl/model/SimulationContext.kt | 8 ++++++-- .../it/unibo/alchemist/dsl/DslLoaderFunctions.kt | 10 ++++++++++ .../kotlin/it/unibo/alchemist/dsl/TestComparison.kt | 5 +++++ .../src/test/resources/dsl/11-monitors.yml | 4 ++++ 5 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 alchemist-loading/src/test/resources/dsl/11-monitors.yml diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt index 317d58a9fb..f48da29e7e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt @@ -10,6 +10,7 @@ package it.unibo.alchemist.boundary.dsl import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.dsl.model.SimulationContext import it.unibo.alchemist.core.Engine import it.unibo.alchemist.core.Simulation @@ -20,7 +21,10 @@ abstract class DslLoader(private val ctx: SimulationContext<*, *>) : Loader { @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation { val environment = ctx.environment as Environment - // Get deployments and add nodes - return Engine(environment) + val engine = Engine(environment) + ctx.monitors.forEach { monitor -> + engine.addOutputMonitor(monitor as OutputMonitor) + } + return engine } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index f63b29eaae..25a1ca51cb 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -12,6 +12,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.DependentVariable import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.Variable import it.unibo.alchemist.boundary.dsl.DslLoader import it.unibo.alchemist.boundary.dsl.model.Incarnation as Inc @@ -28,7 +29,7 @@ import it.unibo.alchemist.model.positions.Euclidean2DPosition import kotlin.jvm.optionals.getOrElse class SimulationContext>(val incarnation: Incarnation, val environment: Environment) { - + var monitors: List> = emptyList() private var _networkModel: LinkingRule = NoLinks() var networkModel: LinkingRule get() = _networkModel @@ -40,10 +41,13 @@ class SimulationContext>(val incarnation: Incarnation, fun deployments(block: DeploymentsContext.() -> Unit) { DeploymentsContext(this).apply(block) } - infix fun addTerminator(predicate: TerminationPredicate<*, *>) { + fun addTerminator(predicate: TerminationPredicate<*, *>) { @Suppress("UNCHECKED_CAST") environment.addTerminator(predicate as TerminationPredicate) } + fun addMonitor(monitor: OutputMonitor) { + monitors = monitors + (monitor) + } } fun > createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 54ef798548..0ecc8822f7 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -7,8 +7,11 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ +@file:Suppress("UNCHECKED_CAST") + package it.unibo.alchemist.dsl +import another.location.SimpleMonitor import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.dsl.model.Incarnation.PROTELIS import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE @@ -250,4 +253,11 @@ object DslLoaderFunctions { } } } + + fun > test11monitors(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + addMonitor(SimpleMonitor()) + } + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt index 07146c8063..2b04dbc485 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt @@ -58,4 +58,9 @@ class TestComparison { fun > test10Environment() { DslLoaderFunctions.test10Environment().shouldEqual("dsl/10-environment.yml") } + + @Test + fun > test11Monitors() { + DslLoaderFunctions.test11monitors().shouldEqual("dsl/11-monitors.yml") + } } diff --git a/alchemist-loading/src/test/resources/dsl/11-monitors.yml b/alchemist-loading/src/test/resources/dsl/11-monitors.yml new file mode 100644 index 0000000000..0d148b8d91 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/11-monitors.yml @@ -0,0 +1,4 @@ +incarnation: sapere + +monitors: + - type: another.location.SimpleMonitor \ No newline at end of file From 1d7f3dccdf220a017ad3542b13dcaf7a283700b1 Mon Sep 17 00:00:00 2001 From: marco Date: Thu, 11 Sep 2025 18:12:28 +0200 Subject: [PATCH 013/196] feat: add support for layers --- .../boundary/dsl/model/LayerContext.kt | 18 +++++ .../boundary/dsl/model/SimulationContext.kt | 14 ++++ .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 30 +++++++ .../alchemist/dsl/LoaderComparisonHelper.kt | 78 +++++++++++++++++++ .../it/unibo/alchemist/dsl/TestComparison.kt | 5 ++ .../src/test/resources/dsl/12-layers.yml | 19 +++++ 6 files changed, 164 insertions(+) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt create mode 100644 alchemist-loading/src/test/resources/dsl/12-layers.yml diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt new file mode 100644 index 0000000000..bc97f7b05c --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.model.Layer +import it.unibo.alchemist.model.Position + +class LayerContext>(ctx: SimulationContext) { + var molecule: String? = null + var layer: Layer? = null +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 25a1ca51cb..bb5302461a 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -19,6 +19,7 @@ import it.unibo.alchemist.boundary.dsl.model.Incarnation as Inc import it.unibo.alchemist.boundary.launchers.DefaultLauncher import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.SupportedIncarnations @@ -30,6 +31,7 @@ import kotlin.jvm.optionals.getOrElse class SimulationContext>(val incarnation: Incarnation, val environment: Environment) { var monitors: List> = emptyList() + private val layers: MutableMap> = HashMap() private var _networkModel: LinkingRule = NoLinks() var networkModel: LinkingRule get() = _networkModel @@ -48,6 +50,18 @@ class SimulationContext>(val incarnation: Incarnation, fun addMonitor(monitor: OutputMonitor) { monitors = monitors + (monitor) } + fun layer(block: LayerContext.() -> Unit) { + val l = LayerContext(this).apply(block) + require(l.layer != null) { "Layer must be specified" } + require(l.molecule != null) { "Molecule must be specified" } + require(!this.layers.containsKey(l.molecule)) { + "Inconsistent layer definition for molecule ${l.molecule}. " + + "There must be a single layer per molecule" + } + val molecule = incarnation.createMolecule(l.molecule) + layers[l.molecule!!] = l.layer!! + environment.addLayer(molecule, l.layer!!) + } } fun > createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 0ecc8822f7..df6edde299 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -23,11 +23,14 @@ import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.deployments.Circle import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.layers.StepLayer import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.maps.actions.ReproduceGPSTrace import it.unibo.alchemist.model.maps.deployments.FromGPSTrace import it.unibo.alchemist.model.maps.environments.OSMEnvironment import it.unibo.alchemist.model.positionfilters.Rectangle +import it.unibo.alchemist.model.positions.Euclidean2DPosition import it.unibo.alchemist.model.reactions.Event import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.timedistributions.DiracComb @@ -260,4 +263,31 @@ object DslLoaderFunctions { addMonitor(SimpleMonitor()) } } + fun > test12Layers(): Loader { + val incarnation = SAPERE.incarnation() + val env = Continuous2DEnvironment(incarnation) + return simulation(incarnation, env) { + layer { + molecule = "A" + layer = StepLayer(2.0, 2.0, 100.0, 0.0) + } + layer { + molecule = "B" + layer = StepLayer(-2.0, -2.0, 0.0, 100.0) + } + deployments { + deploy( + Grid( + environment, generator, + -5.0, -5.0, 5.0, 5.0, 0.25, + 0.1, 0.1, + ), + ) { + all { + molecule = "a" + } + } + } + } + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt index 1cd999b96e..9357fa60cb 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt @@ -127,6 +127,9 @@ object LoaderComparisonHelper { // Compare programs (reactions) comparePrograms(dslEnv, yamlEnv) + + // Compare layers + compareLayers(dslEnv, yamlEnv) } /** @@ -317,6 +320,81 @@ object LoaderComparisonHelper { // How to compare terminators...? } + + /** + * Compares layers between environments + */ + private fun > compareLayers(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing layers...") + + // Simplified check + // If two layers have different molecules this test does not detect it. + + // Compare layer counts + assertEquals( + yamlEnv.layers.size, + dslEnv.layers.size, + "Layer counts should match", + ) + + // Compare layer types + val dslLayerTypes = dslEnv.layers.map { it::class }.sortedBy { it.simpleName } + val yamlLayerTypes = yamlEnv.layers.map { it::class }.sortedBy { it.simpleName } + + assertEquals( + yamlLayerTypes, + dslLayerTypes, + "Layer types should match", + ) + + // Compare layer values at sample positions + compareLayerValues(dslEnv, yamlEnv) + } + + /** + * Compares layer values at sample positions + */ + private fun > compareLayerValues(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing layer values...") + + // Sample positions to test layer values + val samplePositions = mutableListOf

() + + // Add positions from both environments' nodes + samplePositions.addAll(dslEnv.nodes.map { dslEnv.getPosition(it) }) + samplePositions.addAll(yamlEnv.nodes.map { yamlEnv.getPosition(it) }) + + // Remove duplicates + val uniquePositions = samplePositions.distinct() + + if (uniquePositions.isNotEmpty()) { + for (position in uniquePositions) { + val dslLayerValues = dslEnv.layers.map { (it.getValue(position)) } + val yamlLayerValues = yamlEnv.layers.map { it.getValue(position) } + // Convert all values to Double for comparison to handle Int vs Double differences + val dslDoubleValues = dslLayerValues.map { value -> + when (value) { + is Number -> value.toDouble() + else -> value.toString().toDoubleOrNull() ?: 0.0 + } + } + val yamlDoubleValues = yamlLayerValues.map { value -> + when (value) { + is Number -> value.toDouble() + else -> value.toString().toDoubleOrNull() ?: 0.0 + } + } + + assertEquals( + dslDoubleValues, + yamlDoubleValues, + "Layer values at position $position should match", + ) + } + } else { + println("Skipping layer value comparison - no valid positions found") + } + } } /** diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt index 2b04dbc485..429813e1b3 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt @@ -63,4 +63,9 @@ class TestComparison { fun > test11Monitors() { DslLoaderFunctions.test11monitors().shouldEqual("dsl/11-monitors.yml") } + + @Test + fun > test12Layers() { + DslLoaderFunctions.test12Layers().shouldEqual("dsl/12-layers.yml") + } } diff --git a/alchemist-loading/src/test/resources/dsl/12-layers.yml b/alchemist-loading/src/test/resources/dsl/12-layers.yml new file mode 100644 index 0000000000..a54eb56c7c --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/12-layers.yml @@ -0,0 +1,19 @@ +incarnation: sapere + +environment: + type: Continuous2DEnvironment + parameters: [] + +layers: + - type: StepLayer + parameters: [2, 2, 100, 0] + molecule: A + - type: StepLayer + parameters: [-2, -2, 0, 100] + molecule: B + +deployments: + - type: Grid + parameters: [-5, -5, 5, 5, 0.25, 0.1, 0.1] + contents: + molecule: a \ No newline at end of file From 10e556fced00b2acb45d7c2c35c12dc8ed97cfec Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 15 Oct 2025 10:34:44 +0200 Subject: [PATCH 014/196] feat: improve test framework now we also compare two simulations after running them for few steps. --- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 51 ++- .../it/unibo/alchemist/dsl/LoaderFactory.kt | 35 ++ .../alchemist/dsl/RuntimeComparisonHelper.kt | 368 ++++++++++++++++++ .../alchemist/dsl/SimulationsComparisons.kt | 97 +++++ ...sonHelper.kt => StaticComparisonHelper.kt} | 106 +++-- .../it/unibo/alchemist/dsl/TestComparators.kt | 82 ++++ .../it/unibo/alchemist/dsl/TestComparison.kt | 71 ---- 7 files changed, 700 insertions(+), 110 deletions(-) create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/{LoaderComparisonHelper.kt => StaticComparisonHelper.kt} (80%) create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt delete mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index df6edde299..214c243e33 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -7,7 +7,7 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -@file:Suppress("UNCHECKED_CAST") +@file:Suppress("UNCHECKED_CAST", "DEPRECATION") package it.unibo.alchemist.dsl @@ -17,6 +17,10 @@ import it.unibo.alchemist.boundary.dsl.model.Incarnation.PROTELIS import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE import it.unibo.alchemist.boundary.dsl.model.incarnation import it.unibo.alchemist.boundary.dsl.model.simulation +import it.unibo.alchemist.boundary.exporters.CSVExporter +import it.unibo.alchemist.boundary.exportfilters.CommonFilters +import it.unibo.alchemist.boundary.extractors.MoleculeReader +import it.unibo.alchemist.boundary.extractors.Time import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Position @@ -36,6 +40,7 @@ import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.timedistributions.DiracComb import it.unibo.alchemist.model.timedistributions.ExponentialTime import it.unibo.alchemist.model.timedistributions.WeibullTime +import it.unibo.alchemist.test.GlobalTestReaction import org.apache.commons.math3.random.MersenneTwister object DslLoaderFunctions { @@ -49,7 +54,6 @@ object DslLoaderFunctions { } } } - fun > test02ManyNodes(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { @@ -68,7 +72,6 @@ object DslLoaderFunctions { } } } - fun > test03Grid(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { @@ -90,7 +93,6 @@ object DslLoaderFunctions { } } } - fun > test05Content(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { @@ -114,7 +116,6 @@ object DslLoaderFunctions { } } } - fun > test06ContentFiltered(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { @@ -142,6 +143,7 @@ object DslLoaderFunctions { } } + @Suppress("DEPRECATION") fun > test07Programs(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { @@ -174,7 +176,6 @@ object DslLoaderFunctions { } } } - fun > test08ProtelisPrograms(): Loader { val incarnation = PROTELIS.incarnation() return simulation(incarnation) { @@ -194,7 +195,6 @@ object DslLoaderFunctions { } } } - fun > test09TimeDistribution(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { @@ -222,7 +222,6 @@ object DslLoaderFunctions { } } } - fun > test10Environment(): Loader { val incarnation = SAPERE.incarnation() val env = OSMEnvironment(incarnation, "vcm.pbf", false) @@ -256,7 +255,6 @@ object DslLoaderFunctions { } } } - fun > test11monitors(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { @@ -265,8 +263,7 @@ object DslLoaderFunctions { } fun > test12Layers(): Loader { val incarnation = SAPERE.incarnation() - val env = Continuous2DEnvironment(incarnation) - return simulation(incarnation, env) { + return simulation(incarnation) { layer { molecule = "A" layer = StepLayer(2.0, 2.0, 100.0, 0.0) @@ -290,4 +287,36 @@ object DslLoaderFunctions { } } } + fun > test13GlobalReaction(): Loader { + val incarnation = PROTELIS.incarnation() + return simulation(incarnation) { + program( + GlobalTestReaction( + DiracComb(1.0), + environment, + ), + ) + } + } + fun > test14Exporters(): Loader { + val incarnation = PROTELIS.incarnation() + return simulation(incarnation) { + exporter { + type = CSVExporter( + "test_export_interval", + 4.0, + ) + data( + Time(), + MoleculeReader( + "default_module:default_program", + null, + incarnation, + CommonFilters.NOFILTER.filteringPolicy, + emptyList(), + ), + ) + } + } + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt new file mode 100644 index 0000000000..5a45f1c255 --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.boundary.LoadAlchemist +import it.unibo.alchemist.boundary.Loader +import org.kaikikm.threadresloader.ResourceLoader + +/** + * Factory for creating and loading DSL and YAML loaders for testing + */ +object LoaderFactory { + + /** + * Loads a DSL loader from a resource path + */ + fun loadDsl(dslCode: String): Loader = throw Exception("Not implemented yet") + + /** + * Loads a YAML loader from a resource path + */ + fun loadYaml(yamlResource: String): Loader = LoadAlchemist.from(ResourceLoader.getResource(yamlResource)!!) + + /** + * Loads both DSL and YAML loaders for comparison + */ + fun loadBoth(dslCode: String, yamlResource: String): Pair = + Pair(loadDsl(dslCode), loadYaml(yamlResource)) +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt new file mode 100644 index 0000000000..816f85a716 --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.core.Simulation +import it.unibo.alchemist.core.Status +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.terminators.StepCount +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.fail + +/** + * Helper for comparing DSL and YAML loaders by running simulations and comparing final states + * + * This class focuses on runtime behavior comparison by executing both simulations + * for a specified duration and comparing their final states. + * + */ +object RuntimeComparisonHelper { + + /** + * Compares loaders by running both simulations for a specified number of steps + * and comparing their final states + */ + fun > compareLoaders(dslLoader: Loader, yamlLoader: Loader, steps: Long = 1000L) { + println("Running simulations for comparison...") + + val dslSimulation = dslLoader.getDefault() + val yamlSimulation = yamlLoader.getDefault() + + // Add step-based terminators to both simulations + addStepTerminator(dslSimulation, steps) + addStepTerminator(yamlSimulation, steps) + + try { + // Run simulations sequentially to avoid complexity + println("Running DSL simulation...") + runSimulationSynchronously(dslSimulation) + println("DSL simulation completed with status: ${dslSimulation.status}") + + println("Running YAML simulation...") + runSimulationSynchronously(yamlSimulation) + println("YAML simulation completed with status: ${yamlSimulation.status}") + + // Compare final states + compareRuntimeStates(dslSimulation, yamlSimulation) + } catch (e: Exception) { + fail("Error during simulation execution: ${e.message}") + } finally { + // Ensure simulations are terminated (only if not already terminated) + if (dslSimulation.status != Status.TERMINATED) { + dslSimulation.terminate() + } + if (yamlSimulation.status != Status.TERMINATED) { + yamlSimulation.terminate() + } + } + } + + /** + * Adds step-based terminator to a simulation + */ + private fun > addStepTerminator(simulation: Simulation, steps: Long) { + // Add step-based terminator + simulation.environment.addTerminator(StepCount(steps)) + } + + /** + * Runs a simulation synchronously (terminator will stop it) + */ + private fun > runSimulationSynchronously(simulation: Simulation) { + simulation.play() // Start the simulation + simulation.run() // Block until completion (terminator will stop it) + simulation.error.ifPresent { throw it } // Check for errors + } + + /** + * Compares the final states of two simulations after runtime execution + */ + private fun > compareRuntimeStates( + dslSimulation: Simulation, + yamlSimulation: Simulation, + ) { + println("Comparing runtime simulation states...") + + val dslEnv = dslSimulation.environment + val yamlEnv = yamlSimulation.environment + + // Compare simulation execution state + compareSimulationExecutionState(dslSimulation, yamlSimulation) + + // Compare environment states + compareRuntimeEnvironmentStates(dslEnv, yamlEnv) + } + + /** + * Compares simulation execution state (time, step, status, errors) + */ + private fun > compareSimulationExecutionState( + dslSimulation: Simulation, + yamlSimulation: Simulation, + ) { + println("Comparing simulation execution state...") + + // Print simulation times for debugging (skip comparison due to timing variations) + println("DSL simulation time: ${dslSimulation.time}") + println("YAML simulation time: ${yamlSimulation.time}") + val timeDiff = kotlin.math.abs(dslSimulation.time.toDouble() - yamlSimulation.time.toDouble()) + println("Time difference: ${timeDiff}s") + + // Compare step counts + assertEquals( + yamlSimulation.step, + dslSimulation.step, + "Simulation step counts should match", + ) + + // Compare status + assertEquals( + yamlSimulation.status, + dslSimulation.status, + "Simulation status should match", + ) + + // Compare error states + val dslError = dslSimulation.error + val yamlError = yamlSimulation.error + + if (dslError.isPresent != yamlError.isPresent) { + fail( + "Error states differ: DSL has error=${dslError.isPresent}, YAML has error=${yamlError.isPresent}", + ) + } + + if (dslError.isPresent && yamlError.isPresent) { + // Both have errors, compare error messages + val dslErrorMsg = dslError.get().message ?: "Unknown error" + val yamlErrorMsg = yamlError.get().message ?: "Unknown error" + if (dslErrorMsg != yamlErrorMsg) { + fail("Error messages differ: DSL='$dslErrorMsg', YAML='$yamlErrorMsg'") + } + } + } + + /** + * Compares environment states after runtime execution + */ + private fun > compareRuntimeEnvironmentStates( + dslEnv: Environment, + yamlEnv: Environment, + ) { + println("Comparing runtime environment states...") + + // Compare basic environment properties + assertEquals( + yamlEnv.nodeCount, + dslEnv.nodeCount, + "Node counts should match after runtime", + ) + + assertEquals( + yamlEnv.dimensions, + dslEnv.dimensions, + "Environment dimensions should match", + ) + + // Compare node positions and contents + compareRuntimeNodeStates(dslEnv, yamlEnv) + + // Compare global reactions + compareRuntimeGlobalReactions(dslEnv, yamlEnv) + + // Compare layers + compareRuntimeLayers(dslEnv, yamlEnv) + } + + /** + * Compares node states after runtime execution using position-based matching + */ + private fun > compareRuntimeNodeStates(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing runtime node states...") + + // Create position-to-node maps for both environments + val dslNodesByPosition = dslEnv.nodes.associateBy { dslEnv.getPosition(it) } + val yamlNodesByPosition = yamlEnv.nodes.associateBy { yamlEnv.getPosition(it) } + + // Get all unique positions + val allPositions = (dslNodesByPosition.keys + yamlNodesByPosition.keys).distinct() + + for (position in allPositions) { + val dslNode = dslNodesByPosition[position] + val yamlNode = yamlNodesByPosition[position] + + when { + dslNode == null && yamlNode == null -> { + // Both null, continue + } + dslNode == null -> { + fail("DSL simulation missing node at position $position") + } + yamlNode == null -> { + fail("YAML simulation missing node at position $position") + } + else -> { + // Both nodes exist, compare their contents + compareNodeContentsAtPosition(dslNode, yamlNode, position) + } + } + } + } + + /** + * Compares contents of two nodes at the same position + */ + private fun compareNodeContentsAtPosition(dslNode: Node, yamlNode: Node, position: Any) { + // Compare molecule counts + assertEquals( + yamlNode.moleculeCount, + dslNode.moleculeCount, + "Molecule counts should match at position $position", + ) + + // Compare all molecule concentrations + val dslContents = dslNode.contents + val yamlContents = yamlNode.contents + + // Get all unique molecule names + val allMolecules = (dslContents.keys + yamlContents.keys).distinct() + + for (molecule in allMolecules) { + val dslConcentration = dslContents[molecule] + val yamlConcentration = yamlContents[molecule] + + when { + dslConcentration == null && yamlConcentration == null -> { + // Both null, continue + } + dslConcentration == null -> { + fail("DSL node missing molecule $molecule at position $position") + } + yamlConcentration == null -> { + fail("YAML node missing molecule $molecule at position $position") + } + else -> { + // Both concentrations exist, compare them exactly + assertEquals( + yamlConcentration, + dslConcentration, + "Concentration of molecule $molecule should match at position $position", + ) + } + } + } + + // Compare reaction counts + assertEquals( + yamlNode.reactions.size, + dslNode.reactions.size, + "Reaction counts should match at position $position", + ) + } + + /** + * Compares global reactions after runtime execution + */ + private fun > compareRuntimeGlobalReactions( + dslEnv: Environment, + yamlEnv: Environment, + ) { + println("Comparing runtime global reactions...") + + assertEquals( + yamlEnv.globalReactions.size, + dslEnv.globalReactions.size, + "Global reaction counts should match after runtime", + ) + + // Compare global reaction types + val dslGlobalTypes = dslEnv.globalReactions.map { it::class }.sortedBy { it.simpleName } + val yamlGlobalTypes = yamlEnv.globalReactions.map { it::class }.sortedBy { it.simpleName } + + assertEquals( + yamlGlobalTypes, + dslGlobalTypes, + "Global reaction types should match after runtime", + ) + } + + /** + * Compares layers after runtime execution + */ + private fun > compareRuntimeLayers(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing runtime layers...") + + assertEquals( + yamlEnv.layers.size, + dslEnv.layers.size, + "Layer counts should match after runtime", + ) + + // Compare layer types + val dslLayerTypes = dslEnv.layers.map { it::class }.sortedBy { it.simpleName } + val yamlLayerTypes = yamlEnv.layers.map { it::class }.sortedBy { it.simpleName } + + assertEquals( + yamlLayerTypes, + dslLayerTypes, + "Layer types should match after runtime", + ) + + // Compare layer values at sample positions + compareLayerValues(dslEnv, yamlEnv) + } + + /** + * Compares layer values at sample positions + */ + private fun > compareLayerValues(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing layer values...") + + // Sample positions to test layer values + val samplePositions = mutableListOf

() + + // Add positions from both environments' nodes + samplePositions.addAll(dslEnv.nodes.map { dslEnv.getPosition(it) }) + samplePositions.addAll(yamlEnv.nodes.map { yamlEnv.getPosition(it) }) + + // Remove duplicates + val uniquePositions = samplePositions.distinct() + + if (uniquePositions.isNotEmpty()) { + for (position in uniquePositions) { + val dslLayerValues = dslEnv.layers.map { (it.getValue(position)) } + val yamlLayerValues = yamlEnv.layers.map { it.getValue(position) } + // Convert all values to Double for comparison to handle Int vs Double differences + val dslDoubleValues = dslLayerValues.map { value -> + when (value) { + is Number -> value.toDouble() + else -> value.toString().toDoubleOrNull() ?: 0.0 + } + } + val yamlDoubleValues = yamlLayerValues.map { value -> + when (value) { + is Number -> value.toDouble() + else -> value.toString().toDoubleOrNull() ?: 0.0 + } + } + + assertEquals( + dslDoubleValues, + yamlDoubleValues, + "Layer values at position $position should match", + ) + } + } else { + println("Skipping layer value comparison - no valid positions found") + } + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt new file mode 100644 index 0000000000..8e68b0f346 --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.model.Position +import org.junit.jupiter.api.Test + +/** + * Example test demonstrating the new refactored comparison architecture + */ +class SimulationsComparisons { + + @Test + fun > test01() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test01Nodes() }.shouldEqual("dsl/01-nodes.yml") + } + + @Test + fun > test02() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test02ManyNodes() }.shouldEqual("dsl/02-manynodes.yml") + } + + @Test + fun > test03() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test03Grid() }.shouldEqual("dsl/03-grid.yml") + } + + @Test + fun > test05() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test05Content() }.shouldEqual("dsl/05-content.yml") + } + + @Test + fun > test06() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test06ContentFiltered() }.shouldEqual("dsl/06-filters.yml") + } + + @Test + fun > test07() { + // Compare with YAML using static comparison only (includeRuntime = false) + + { DslLoaderFunctions.test07Programs() }.shouldEqual("dsl/07-program.yml") + } + + @Test + fun > test08() { + // Compare with YAML using static comparison only (includeRuntime = false) + DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/08-protelisprogram.yml") + } + + @Test + fun > test09() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test09TimeDistribution() }.shouldEqual("dsl/09-timedistribution.yml") + } + + @Test + fun > test10() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/10-environment.yml") + } + + @Test + fun > test11() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test11monitors() }.shouldEqual("dsl/11-monitors.yml") + } + + @Test + fun > test12() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test12Layers() }.shouldEqual("dsl/12-layers.yml") + } + + @Test + fun > test13() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test13GlobalReaction() }.shouldEqual("dsl/13-globalreaction.yml") + } + + @Test + fun > test14() { + // Compare with YAML using static comparison only (includeRuntime = false) + { DslLoaderFunctions.test14Exporters() }.shouldEqual("dsl/14-exporters.yml") + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt similarity index 80% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt index 9357fa60cb..0d91437e33 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt @@ -8,37 +8,27 @@ */ package it.unibo.alchemist.dsl -import it.unibo.alchemist.boundary.LoadAlchemist +import it.unibo.alchemist.boundary.Exporter import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.exporters.GlobalExporter import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import org.junit.jupiter.api.Assertions.assertEquals -import org.kaikikm.threadresloader.ResourceLoader /** - * Test helper for comparing DSL and YAML loaders + * Helper for comparing static properties of DSL and YAML loaders + * + * This class focuses on comparing the initial state and configuration + * of loaders without running the simulations. */ -object LoaderComparisonHelper { - - /** - * Compares a DSL loader with a YAML loader to ensure they produce equivalent simulations - */ - fun > compareLoaders(dslLoader: Loader, yamlResource: String) { - val yamlLoader = LoadAlchemist.from(ResourceLoader.getResource(yamlResource)!!) - - // Compare basic properties - compareBasicProperties(dslLoader, yamlLoader) - - // Compare simulations - compareSimulations(dslLoader, yamlLoader) - } +object StaticComparisonHelper { /** * Compares basic loader properties */ - private fun compareBasicProperties(dslLoader: Loader, yamlLoader: Loader) { + fun compareBasicProperties(dslLoader: Loader, yamlLoader: Loader) { println("Comparing basic properties...") // Compare constants @@ -80,7 +70,7 @@ object LoaderComparisonHelper { /** * Compares the simulations generated by both loaders */ - private fun > compareSimulations(dslLoader: Loader, yamlLoader: Loader) { + fun > compareSimulations(dslLoader: Loader, yamlLoader: Loader) { println("Comparing simulations...") val dslSimulation = dslLoader.getDefault() @@ -318,7 +308,75 @@ object LoaderComparisonHelper { "Output monitor types should match", ) - // How to compare terminators...? + compareExporters(dslSimulation, yamlSimulation) + } + + private fun compareExporters(dslSimulation: Simulation<*, *>, yamlSimulation: Simulation<*, *>) { + val dslExporters = dslSimulation.outputMonitors + .filterIsInstance>() + .flatMap { it.exporters } + val yamlExporters = yamlSimulation.outputMonitors + .filterIsInstance>() + .flatMap { it.exporters } + + assertEquals( + yamlExporters.size, + dslExporters.size, + "Exporter counts should match", + ) + + val dslTypes = dslExporters.map { it::class }.sortedBy { it.simpleName } + val yamlTypes = yamlExporters.map { it::class }.sortedBy { it.simpleName } + assertEquals( + yamlTypes, + dslTypes, + "Exporter types should match", + ) + + compareDataExtractors(dslExporters, yamlExporters) + } + + private fun compareDataExtractors(dslExporters: List>, yamlExporters: List>) { + val dslTotal = dslExporters.sumOf { it.dataExtractors.size } + val yamlTotal = yamlExporters.sumOf { it.dataExtractors.size } + assertEquals( + yamlTotal, + dslTotal, + "Total data extractor counts should match", + ) + + val dslTypes = dslExporters.flatMap { it.dataExtractors }.map { it::class }.sortedBy { it.simpleName } + val yamlTypes = yamlExporters.flatMap { it.dataExtractors }.map { it::class }.sortedBy { it.simpleName } + assertEquals( + yamlTypes, + dslTypes, + "Data extractor types should match", + ) + + val dslInfo = dslExporters.flatMap { it.dataExtractors }.map { extractor -> + ExtractorInfo( + type = extractor::class.simpleName.orEmpty(), + columns = extractor.columnNames.sorted(), + ) + }.sortedBy { it.toString() } + val yamlInfo = yamlExporters.flatMap { it.dataExtractors }.map { extractor -> + ExtractorInfo( + type = extractor::class.simpleName.orEmpty(), + columns = extractor.columnNames.sorted(), + ) + }.sortedBy { it.toString() } + assertEquals( + yamlInfo, + dslInfo, + "Data extractor information (types and column names) should match", + ) + } + + private data class ExtractorInfo( + val type: String, + val columns: List, + ) { + override fun toString(): String = "Extractor(type=$type, columns=$columns)" } /** @@ -396,11 +454,3 @@ object LoaderComparisonHelper { } } } - -/** - * Extension function for easier test writing - */ -fun Loader.shouldEqual(yamlResource: String) { - @Suppress("UNCHECKED_CAST") - LoaderComparisonHelper.compareLoaders(this, yamlResource) -} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt new file mode 100644 index 0000000000..82538f2896 --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.model.Position + +/** + * Main test comparison class that handles static and runtime comparisons + * + * This class provides an interface for comparing DSL and YAML loaders + * with the option to include runtime behavior testing. + */ +object TestComparators { + + /** + * Compares a DSL loader with a YAML loader + * + * @param dslLoader The DSL loader to compare + * @param yamlResource The YAML resource path to compare against + * @param includeRuntime Whether to include runtime behavior comparison + * @param steps The number of steps for runtime comparison (only used if includeRuntime is true) + */ + fun > compare( + dslLoader: () -> Loader, + yamlResource: String, + includeRuntime: Boolean = false, + steps: Long = 1000L, + ) { + val yamlLoader = LoaderFactory.loadYaml(yamlResource) + + // Always perform static comparison + StaticComparisonHelper.compareBasicProperties(dslLoader(), yamlLoader) + StaticComparisonHelper.compareSimulations(dslLoader(), yamlLoader) + + // Optionally perform runtime comparison + if (includeRuntime) { + RuntimeComparisonHelper.compareLoaders(dslLoader(), yamlLoader, steps) + } + } + + /** + * Compares DSL code with a YAML resource + * + * @param dslCode The DSL code resource path + * @param yamlResource The YAML resource path to compare against + * @param includeRuntime Whether to include runtime behavior comparison + * @param steps The number of steps for runtime comparison (only used if includeRuntime is true) + */ + fun > compare( + dslCode: String, + yamlResource: String, + includeRuntime: Boolean = false, + steps: Long = 3000L, + ) { + compare({ + LoaderFactory.loadDsl(dslCode) + }, yamlResource, includeRuntime, steps) + } +} + +/** + * Extension function for easier test writing with static comparison only + */ +fun Loader.shouldEqual(yamlResource: String) { + @Suppress("UNCHECKED_CAST") + TestComparators.compare({ this }, yamlResource, includeRuntime = false) +} + +/** + * Extension function for comparing DSL function with YAML resource + */ +fun (() -> Loader).shouldEqual(yamlResource: String, includeRuntime: Boolean = true, steps: Long = 3000L) { + @Suppress("UNCHECKED_CAST") + TestComparators.compare(this, yamlResource, includeRuntime, steps) +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt deleted file mode 100644 index 429813e1b3..0000000000 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparison.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.dsl - -import it.unibo.alchemist.model.Position -import org.junit.jupiter.api.Test - -class TestComparison { - - @Test - fun > test01Nodes() { - DslLoaderFunctions.test01Nodes().shouldEqual("dsl/01-nodes.yml") - } - - @Test - fun > test02ManyNodes() { - DslLoaderFunctions.test02ManyNodes().shouldEqual("dsl/02-manynodes.yml") - } - - @Test - fun > test03Grid() { - DslLoaderFunctions.test03Grid().shouldEqual("dsl/03-grid.yml") - } - - @Test - fun > test05Content() { - DslLoaderFunctions.test05Content().shouldEqual("dsl/05-content.yml") - } - - @Test - fun > test06ContentFiltered() { - DslLoaderFunctions.test06ContentFiltered().shouldEqual("dsl/06-filters.yml") - } - - @Test - fun > test07Programs() { - DslLoaderFunctions.test07Programs().shouldEqual("dsl/07-program.yml") - } - - @Test - fun > test08ProtelisPrograms() { - DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/08-protelisprogram.yml") - } - - @Test - fun > test09TimeDistribution() { - DslLoaderFunctions.test09TimeDistribution().shouldEqual("dsl/09-timedistribution.yml") - } - - @Test - fun > test10Environment() { - DslLoaderFunctions.test10Environment().shouldEqual("dsl/10-environment.yml") - } - - @Test - fun > test11Monitors() { - DslLoaderFunctions.test11monitors().shouldEqual("dsl/11-monitors.yml") - } - - @Test - fun > test12Layers() { - DslLoaderFunctions.test12Layers().shouldEqual("dsl/12-layers.yml") - } -} From 4f3b1d5c845e8c4c58b382c1fa1d31044521cb2a Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 15 Oct 2025 10:40:40 +0200 Subject: [PATCH 015/196] feat: add support for exporters and global reactions --- .../unibo/alchemist/boundary/dsl/DslLoader.kt | 26 +++++++++++++++++++ .../boundary/dsl/model/ExporterContext.kt | 23 ++++++++++++++++ .../boundary/dsl/model/SimulationContext.kt | 14 +++++++++- .../test/resources/dsl/13-globalreaction.yml | 9 +++++++ .../src/test/resources/dsl/14-exporters.yml | 9 +++++++ 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt create mode 100644 alchemist-loading/src/test/resources/dsl/13-globalreaction.yml create mode 100644 alchemist-loading/src/test/resources/dsl/14-exporters.yml diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt index f48da29e7e..16e58a7c7f 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt @@ -9,9 +9,11 @@ package it.unibo.alchemist.boundary.dsl +import it.unibo.alchemist.boundary.Exporter import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.dsl.model.SimulationContext +import it.unibo.alchemist.boundary.exporters.GlobalExporter import it.unibo.alchemist.core.Engine import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.model.Environment @@ -21,10 +23,34 @@ abstract class DslLoader(private val ctx: SimulationContext<*, *>) : Loader { @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation { val environment = ctx.environment as Environment + println("Creating engine") val engine = Engine(environment) + val unknownVariableNames = values.keys - variables.keys + require(unknownVariableNames.isEmpty()) { + "Unknown variables provided: $unknownVariableNames." + + " Valid names: ${variables.keys}. Provided: ${values.keys}" + } + // VARIABLE REIFICATION + val variableValues = variables.mapValues { (name, previous) -> + if (values.containsKey(name)) values[name] else previous.default + } + // MONITORS ctx.monitors.forEach { monitor -> engine.addOutputMonitor(monitor as OutputMonitor) } + // EXPORTERS + val exporters = ctx.exporters.map { + it.type.apply { + it.type?.bindDataExtractors(it.extractors) + } + } as List> + + exporters.forEach { it.bindVariables(variableValues) } + + if (exporters.isNotEmpty()) { + engine.addOutputMonitor(GlobalExporter(exporters)) + } + return engine } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt new file mode 100644 index 0000000000..6b2b777f07 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.Exporter +import it.unibo.alchemist.boundary.Extractor +import it.unibo.alchemist.model.Position + +class ExporterContext>(ctx: SimulationContext) { + var type: Exporter? = null + var extractors: List> = emptyList() + + fun data(vararg extractors: Extractor<*>) { + this.extractors = extractors.toList() + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index bb5302461a..7b0c4d6728 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -18,6 +18,7 @@ import it.unibo.alchemist.boundary.dsl.DslLoader import it.unibo.alchemist.boundary.dsl.model.Incarnation as Inc import it.unibo.alchemist.boundary.launchers.DefaultLauncher import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.GlobalReaction import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.LinkingRule @@ -31,6 +32,8 @@ import kotlin.jvm.optionals.getOrElse class SimulationContext>(val incarnation: Incarnation, val environment: Environment) { var monitors: List> = emptyList() + var exporters: List> = emptyList() + var launcher: Launcher? = null private val layers: MutableMap> = HashMap() private var _networkModel: LinkingRule = NoLinks() var networkModel: LinkingRule @@ -50,6 +53,15 @@ class SimulationContext>(val incarnation: Incarnation, fun addMonitor(monitor: OutputMonitor) { monitors = monitors + (monitor) } + fun addLauncher(launcher: Launcher) { + this.launcher = launcher + } + fun exporter(block: ExporterContext.() -> Unit) { + exporters = exporters + ExporterContext(this).apply(block) + } + fun program(program: GlobalReaction) { + this.environment.addGlobalReaction(program) + } fun layer(block: LayerContext.() -> Unit) { val l = LayerContext(this).apply(block) require(l.layer != null) { "Layer must be specified" } @@ -69,7 +81,7 @@ fun > createLoader(simBuilder: SimulationContext): Load override val dependentVariables: Map> = emptyMap() override val variables: Map> = emptyMap() override val remoteDependencies: List = emptyList() - override val launcher: Launcher = DefaultLauncher() + override val launcher: Launcher = simBuilder.launcher ?: DefaultLauncher() } fun > Inc.incarnation(): Incarnation = SupportedIncarnations.get(this.name).getOrElse { diff --git a/alchemist-loading/src/test/resources/dsl/13-globalreaction.yml b/alchemist-loading/src/test/resources/dsl/13-globalreaction.yml new file mode 100644 index 0000000000..c1e030c6c2 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/13-globalreaction.yml @@ -0,0 +1,9 @@ +incarnation: protelis + +environment: + type: Continuous2DEnvironment + global-programs: + - time-distribution: + type: DiracComb + parameters: [1.0] + type: GlobalTestReaction diff --git a/alchemist-loading/src/test/resources/dsl/14-exporters.yml b/alchemist-loading/src/test/resources/dsl/14-exporters.yml new file mode 100644 index 0000000000..768b46c188 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/14-exporters.yml @@ -0,0 +1,9 @@ +incarnation: protelis +export: + - type: CSVExporter + parameters: + fileNameRoot: "test_export_interval" + interval: 3.0 + data: + - time + - molecule: "default_module:default_program" From 9fb52a4550f76d4fba48876d75ab91b7cadaacf2 Mon Sep 17 00:00:00 2001 From: marco Date: Thu, 16 Oct 2025 00:08:27 +0200 Subject: [PATCH 016/196] feat: add support for variables using delegates --- .../unibo/alchemist/boundary/dsl/DslLoader.kt | 16 +++- .../boundary/dsl/model/SimulationContext.kt | 76 ++++++++++------- .../boundary/dsl/model/VariablesContext.kt | 64 ++++++++++++++ .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 38 ++++++++- .../alchemist/dsl/RuntimeComparisonHelper.kt | 3 +- .../alchemist/dsl/SimulationsComparisons.kt | 22 ++--- .../alchemist/dsl/StaticComparisonHelper.kt | 35 +++++--- .../it/unibo/alchemist/dsl/TestVariables.kt | 84 +++++++++++++++++++ .../src/test/resources/dsl/15-variables.yml | 35 ++++++++ 9 files changed, 306 insertions(+), 67 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt create mode 100644 alchemist-loading/src/test/resources/dsl/15-variables.yml diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt index 16e58a7c7f..ea608a5e32 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt @@ -22,8 +22,13 @@ import it.unibo.alchemist.model.Position abstract class DslLoader(private val ctx: SimulationContext<*, *>) : Loader { @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation { + values.forEach { (t, u) -> + ctx.variablesContext.references[t] = u as Any + } + println("applying dsl with this values" + ctx.variablesContext.references) + println("Build steps" + ctx.buildSteps) + ctx.build() // variables passing val environment = ctx.environment as Environment - println("Creating engine") val engine = Engine(environment) val unknownVariableNames = values.keys - variables.keys require(unknownVariableNames.isEmpty()) { @@ -31,9 +36,12 @@ abstract class DslLoader(private val ctx: SimulationContext<*, *>) : Loader { " Valid names: ${variables.keys}. Provided: ${values.keys}" } // VARIABLE REIFICATION - val variableValues = variables.mapValues { (name, previous) -> - if (values.containsKey(name)) values[name] else previous.default - } + val variableValues = ctx.variablesContext.references.plus( + ctx.variablesContext.dependentVariables.map { (k, v) -> + k to v() + }, + ) + // MONITORS ctx.monitors.forEach { monitor -> engine.addOutputMonitor(monitor as OutputMonitor) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 7b0c4d6728..78222cb30e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -7,6 +7,8 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ +@file:Suppress("UNCHECKED_CAST") + package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.DependentVariable @@ -28,12 +30,15 @@ import it.unibo.alchemist.model.TerminationPredicate import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.linkingrules.NoLinks import it.unibo.alchemist.model.positions.Euclidean2DPosition +import java.io.Serializable import kotlin.jvm.optionals.getOrElse class SimulationContext>(val incarnation: Incarnation, val environment: Environment) { - var monitors: List> = emptyList() - var exporters: List> = emptyList() - var launcher: Launcher? = null + val buildSteps: MutableList<() -> Unit> = mutableListOf() + val monitors: MutableList> = mutableListOf() + val exporters: MutableList> = mutableListOf() + var launcher: Launcher = DefaultLauncher() + private val layers: MutableMap> = HashMap() private var _networkModel: LinkingRule = NoLinks() var networkModel: LinkingRule @@ -42,46 +47,56 @@ class SimulationContext>(val incarnation: Incarnation, _networkModel = value environment.linkingRule = value } + val variablesContext = VariablesContext() + fun build() { + buildSteps.forEach { it() } + } fun deployments(block: DeploymentsContext.() -> Unit) { - DeploymentsContext(this).apply(block) + buildSteps.add { DeploymentsContext(this).apply(block) } } fun addTerminator(predicate: TerminationPredicate<*, *>) { @Suppress("UNCHECKED_CAST") - environment.addTerminator(predicate as TerminationPredicate) + buildSteps.add { environment.addTerminator(predicate as TerminationPredicate) } } fun addMonitor(monitor: OutputMonitor) { - monitors = monitors + (monitor) - } - fun addLauncher(launcher: Launcher) { - this.launcher = launcher + buildSteps.add { monitors.add(monitor) } } fun exporter(block: ExporterContext.() -> Unit) { - exporters = exporters + ExporterContext(this).apply(block) + buildSteps.add { exporters.add(ExporterContext(this).apply(block)) } } fun program(program: GlobalReaction) { - this.environment.addGlobalReaction(program) + buildSteps.add { this.environment.addGlobalReaction(program) } + } + fun runLater(block: () -> Unit) { + buildSteps.add { block() } } fun layer(block: LayerContext.() -> Unit) { - val l = LayerContext(this).apply(block) - require(l.layer != null) { "Layer must be specified" } - require(l.molecule != null) { "Molecule must be specified" } - require(!this.layers.containsKey(l.molecule)) { - "Inconsistent layer definition for molecule ${l.molecule}. " + - "There must be a single layer per molecule" + buildSteps.add { + val l = LayerContext(this).apply(block) + require(l.layer != null) { "Layer must be specified" } + require(l.molecule != null) { "Molecule must be specified" } + require(!this.layers.containsKey(l.molecule)) { + "Inconsistent layer definition for molecule ${l.molecule}. " + + "There must be a single layer per molecule" + } + val molecule = incarnation.createMolecule(l.molecule) + layers[l.molecule!!] = l.layer!! + environment.addLayer(molecule, l.layer!!) } - val molecule = incarnation.createMolecule(l.molecule) - layers[l.molecule!!] = l.layer!! - environment.addLayer(molecule, l.layer!!) } + fun variable(source: Variable): VariablesContext.VariableProvider = + variablesContext.register(source) + fun variable(source: () -> T): VariablesContext.DependentVariableProvider = + variablesContext.dependent(source) } -fun > createLoader(simBuilder: SimulationContext): Loader = object : DslLoader(simBuilder) { - override val constants: Map = emptyMap() - override val dependentVariables: Map> = emptyMap() - override val variables: Map> = emptyMap() - override val remoteDependencies: List = emptyList() - override val launcher: Launcher = simBuilder.launcher ?: DefaultLauncher() +fun > createLoader(dsl: SimulationContext): Loader = object : DslLoader(dsl) { + override val constants: Map = emptyMap() // not needed + override val dependentVariables: Map> = emptyMap() // not needed + override val variables: Map> = dsl.variablesContext.variables + override val remoteDependencies: List = emptyList() // TODO: to implement + override val launcher: Launcher = dsl.launcher } fun > Inc.incarnation(): Incarnation = SupportedIncarnations.get(this.name).getOrElse { @@ -92,10 +107,7 @@ fun > simulation( incarnation: Incarnation, environment: Environment, block: SimulationContext.() -> Unit, -): Loader { - val sim = SimulationContext(incarnation, environment).apply(block) - return createLoader(sim) -} +): Loader = createLoader(SimulationContext(incarnation, environment).apply(block)) fun > simulation( incarnation: Incarnation, @@ -103,6 +115,6 @@ fun > simulation( ): Loader { @Suppress("UNCHECKED_CAST") val defaultEnv = Continuous2DEnvironment(incarnation as Incarnation) - val sim = SimulationContext(incarnation, defaultEnv).apply(block) - return createLoader(sim) + val ctx = SimulationContext(incarnation, defaultEnv).apply(block) + return createLoader(ctx) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt new file mode 100644 index 0000000000..240bb4e602 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.Variable +import java.io.Serializable +import kotlin.properties.ReadOnlyProperty +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +class VariablesContext { + val references: MutableMap = mutableMapOf() + val variables: MutableMap> = mutableMapOf() + val dependentVariables: MutableMap Any> = mutableMapOf() + + fun register(source: Variable): VariableProvider = VariableProvider(source) + fun dependent(source: () -> T): DependentVariableProvider = DependentVariableProvider(source) + + inner class DependentVariableProvider(private val source: () -> T) { + operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty { + if (variables.containsKey(prop.name) || dependentVariables.contains(prop.name)) { + throw IllegalStateException("Variable ${prop.name} already exists") + } + dependentVariables.put(prop.name, source) + return DependentRef(source) + } + } + inner class DependentRef(private val source: () -> T) : ReadWriteProperty { + override fun getValue(thisRef: Any?, property: KProperty<*>): T = source() + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T): Unit = + throw IllegalStateException("Not allowed to assign a value to the variable ${property.name}") + } + inner class VariableProvider(private val source: Variable<*>) { + operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty { + if (variables.containsKey(prop.name) || dependentVariables.contains(prop.name)) { + throw IllegalStateException("Variable ${prop.name} already exists") + } + variables[prop.name] = source + references[prop.name] = source.default + return Ref() + } + } + + inner class Ref : ReadWriteProperty { + override fun getValue(thisRef: Any?, property: KProperty<*>): T { + if (!references.contains(property.name)) { + throw IllegalStateException("Variable ${property.name} has no defined value") + } + @Suppress("UNCHECKED_CAST") + return references[property.name] as T + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T): Unit = + throw IllegalStateException("Not allowed to assign a value to the variable ${property.name}") + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 214c243e33..62ee4cd172 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -21,13 +21,14 @@ import it.unibo.alchemist.boundary.exporters.CSVExporter import it.unibo.alchemist.boundary.exportfilters.CommonFilters import it.unibo.alchemist.boundary.extractors.MoleculeReader import it.unibo.alchemist.boundary.extractors.Time +import it.unibo.alchemist.boundary.variables.GeometricVariable +import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.deployments.Circle import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point -import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.layers.StepLayer import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.maps.actions.ReproduceGPSTrace @@ -319,4 +320,39 @@ object DslLoaderFunctions { } } } + fun > test15Variables(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) + val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + + val mSize by variable { -size } + val sourceStart by variable { mSize / 10.0 } + val sourceSize by variable { size / 5.0 } + + networkModel = ConnectWithinDistance(0.5) + deployments { + deploy( + Grid( + environment, generator, + mSize, mSize, size, size, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + inside(Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { + molecule = "token, 0, []" + } + programs { + all { + timeDistribution(rate.toString()) + program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" + } + all { + program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" + } + } + } + } + } + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt index 816f85a716..1c6bc9aade 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt @@ -15,6 +15,7 @@ import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.terminators.StepCount +import kotlin.math.abs import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.fail @@ -114,7 +115,7 @@ object RuntimeComparisonHelper { // Print simulation times for debugging (skip comparison due to timing variations) println("DSL simulation time: ${dslSimulation.time}") println("YAML simulation time: ${yamlSimulation.time}") - val timeDiff = kotlin.math.abs(dslSimulation.time.toDouble() - yamlSimulation.time.toDouble()) + val timeDiff = abs(dslSimulation.time.toDouble() - yamlSimulation.time.toDouble()) println("Time difference: ${timeDiff}s") // Compare step counts diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt index 8e68b0f346..31521f78e6 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt @@ -11,87 +11,75 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.model.Position import org.junit.jupiter.api.Test -/** - * Example test demonstrating the new refactored comparison architecture - */ class SimulationsComparisons { @Test fun > test01() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test01Nodes() }.shouldEqual("dsl/01-nodes.yml") } @Test fun > test02() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test02ManyNodes() }.shouldEqual("dsl/02-manynodes.yml") } @Test fun > test03() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test03Grid() }.shouldEqual("dsl/03-grid.yml") } @Test fun > test05() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test05Content() }.shouldEqual("dsl/05-content.yml") } @Test fun > test06() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test06ContentFiltered() }.shouldEqual("dsl/06-filters.yml") } @Test fun > test07() { - // Compare with YAML using static comparison only (includeRuntime = false) - { DslLoaderFunctions.test07Programs() }.shouldEqual("dsl/07-program.yml") } @Test fun > test08() { - // Compare with YAML using static comparison only (includeRuntime = false) DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/08-protelisprogram.yml") } @Test fun > test09() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test09TimeDistribution() }.shouldEqual("dsl/09-timedistribution.yml") } @Test fun > test10() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/10-environment.yml") } @Test fun > test11() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test11monitors() }.shouldEqual("dsl/11-monitors.yml") } @Test fun > test12() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test12Layers() }.shouldEqual("dsl/12-layers.yml") } @Test fun > test13() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test13GlobalReaction() }.shouldEqual("dsl/13-globalreaction.yml") } @Test fun > test14() { - // Compare with YAML using static comparison only (includeRuntime = false) { DslLoaderFunctions.test14Exporters() }.shouldEqual("dsl/14-exporters.yml") } + + @Test + fun > test15() { + { DslLoaderFunctions.test15Variables() }.shouldEqual("dsl/15-variables.yml") + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt index 0d91437e33..33f2fcd06d 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt @@ -38,19 +38,30 @@ object StaticComparisonHelper { "Constants should match", ) - // Compare variables + // Compare variables by name, default value, and full stream + val yamlVariables = yamlLoader.variables + val dslVariables = dslLoader.variables assertEquals( - yamlLoader.variables, - dslLoader.variables, - "Variables should match", - ) - - // Compare dependent variables - assertEquals( - yamlLoader.dependentVariables, - dslLoader.dependentVariables, - "Dependent variables should match", + yamlVariables.keys, + dslVariables.keys, + "Variable names should match", ) + yamlVariables.keys.forEach { name -> + val yamlVar = yamlVariables.getValue(name) + val dslVar = dslVariables.getValue(name) + assertEquals( + yamlVar.default, + dslVar.default, + "Default value of variable '$name' should match", + ) + val yamlValues = yamlVar.stream().toList() + val dslValues = dslVar.stream().toList() + assertEquals( + yamlValues, + dslValues, + "Values stream of variable '$name' should match", + ) + } // Compare remote dependencies assertEquals( @@ -73,8 +84,8 @@ object StaticComparisonHelper { fun > compareSimulations(dslLoader: Loader, yamlLoader: Loader) { println("Comparing simulations...") - val dslSimulation = dslLoader.getDefault() val yamlSimulation = yamlLoader.getDefault() + val dslSimulation = dslLoader.getDefault() // Compare environments compareEnvironments(dslSimulation.environment, yamlSimulation.environment) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt new file mode 100644 index 0000000000..bed366f6ea --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.dsl + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.booleans.shouldBeTrue +import io.kotest.matchers.doubles.shouldBeExactly +import io.kotest.matchers.shouldBe +import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE +import it.unibo.alchemist.boundary.dsl.model.incarnation +import it.unibo.alchemist.boundary.dsl.model.simulation +import it.unibo.alchemist.boundary.variables.GeometricVariable +import it.unibo.alchemist.boundary.variables.LinearVariable +import it.unibo.alchemist.model.Position +import org.junit.jupiter.api.Test + +class TestVariables { + @Test + fun > testDefaultValue() { + val incarnation = SAPERE.incarnation() + simulation(incarnation) { + val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + + runLater { + println("Checking variable") + rate.shouldBeExactly(5.0) + variablesContext.variables.containsKey("rate").shouldBeTrue() + } + }.getDefault() // needed to build the simulation + } + + @Test + fun > testOverrideValue() { + val incarnation = SAPERE.incarnation() + val loader = simulation(incarnation) { + val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + deployments { + rate.shouldBeExactly(20.0) + variablesContext.variables.containsKey("rate").shouldBeTrue() + } + } + loader.getWith(mapOf(("rate" to 20.0))) + } + + @Test + fun > testDoubleDeclaration() { + val incarnation = SAPERE.incarnation() + simulation(incarnation) { + val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + shouldThrow { + val rate: Double by variable(GeometricVariable(2.0, 1.0, 5.0, 1)) + } + } + } + + @Test + fun > testDependendVariable() { + val incarnation = SAPERE.incarnation() + val loader = simulation(incarnation) { + val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) + val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + + val mSize by variable { -size } + val sourceStart by variable { mSize / 10.0 } + val sourceSize by variable { size / 5.0 } + + runLater { + rate.shouldBe(2.0) + size.shouldBe(10.0) + mSize.shouldBe(-10.0) + sourceStart.shouldBe(-1.0) + sourceSize.shouldBe(2.0) + } + } + loader.getWith(mapOf("size" to 10.0)) + } +} diff --git a/alchemist-loading/src/test/resources/dsl/15-variables.yml b/alchemist-loading/src/test/resources/dsl/15-variables.yml new file mode 100644 index 0000000000..35eb15c1ac --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/15-variables.yml @@ -0,0 +1,35 @@ +incarnation: sapere + +variables: + rate: &rate + type: GeometricVariable + parameters: [2, 0.1, 10, 9] + size: &size + type: LinearVariable + parameters: [5, 1, 10, 1] + mSize: &mSize + formula: -size + sourceStart: &sourceStart + formula: mSize / 10 + sourceSize: &sourceSize + formula: size / 5 + +network-model: + type: ConnectWithinDistance + parameters: [0.5] + +_send: &grad + - time-distribution: *rate + program: "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" + - program: > + {token, N, L}{token, def: N2>=N, L2} --> {token, N, L} + +deployments: + type: Grid + parameters: [*mSize, *mSize, *size, *size, 0.25, 0.25, 0.1, 0.1] + contents: + - in: + type: Rectangle + parameters: [*sourceStart, *sourceStart, *sourceSize, *sourceSize] + molecule: token, 0, [] + programs: *grad From 6e2d517587c896032a201a2d33c24a2797018ef5 Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 27 Oct 2025 17:03:43 +0100 Subject: [PATCH 017/196] fix: fix seeds problem --- .../boundary/dsl/model/DeploymentsContext.kt | 153 +++++++----------- .../boundary/dsl/model/ProgramsContext.kt | 97 +++++++++++ .../boundary/dsl/model/SimulationContext.kt | 41 +---- 3 files changed, 156 insertions(+), 135 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index 61ba9df645..8f97d2658f 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -9,149 +9,104 @@ package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.model.Action -import it.unibo.alchemist.model.Condition +import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter -import it.unibo.alchemist.model.Reaction -import it.unibo.alchemist.model.TimeDistribution -import org.apache.commons.math3.random.MersenneTwister -import org.apache.commons.math3.random.RandomGenerator -class DeploymentsContext>(ctx: SimulationContext) { - var generator: RandomGenerator = MersenneTwister(10) +class DeploymentsContext>(val ctx: SimulationContext) { val environment: Environment<*, *> = ctx.environment as Environment<*, *> val env = ctx.environment + var generator = ctx.scenarioGenerator private val inc = ctx.incarnation + // deployment -> node -> molecule -> concentration -> program( timedistribution -> reaction + actions + conditions) fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) { + logger.debug("Deploying deployment: {}", deployment) @Suppress("UNCHECKED_CAST") - addNodes(deployment as Deployment

) - DeploymentContext().apply(block) + val d = DeploymentContext(deployment as Deployment

).apply(block) + // populate + populateDeployment(d) } fun deploy(deployment: Deployment<*>) { @Suppress("UNCHECKED_CAST") this.deploy(deployment) {} } - private fun addNodes(deployment: Deployment

) { - deployment.forEach { position -> + private fun populateDeployment(deploymentContext: DeploymentContext) { + val deployment = deploymentContext.deployment + deployment.stream().forEach { position -> + logger.debug("visiting position: {} for deployment: {}", position, deployment) + logger.debug("creaing node for deployment: {}", deployment) val node = inc.createNode( - generator, + ctx.simulationGenerator, env, null, ) + // TODO: add support for custom nodes + // TODO: load properties + // load contents + val contents = deploymentContext.contents + for (content in contents) { + deploymentContext.applyToNodes(node, position, content) + } + // load programs + val programs = deploymentContext.programsContext.programs + for (programEntry in programs) { + deploymentContext.programsContext.applyToNodes( + node, + position, + programEntry.program, + programEntry.filter, + ) + } + logger.debug("Adding node to environment at position: {}", position) env.addNode(node, position) } } - inner class DeploymentContext { + inner class DeploymentContext(val deployment: Deployment

) { + val contents: MutableList = mutableListOf() + val programsContext: ProgramsContext = ProgramsContext(this@DeploymentsContext) + init { + logger.debug("Visiting deployment: {}", deployment) + } fun all(block: ContentContext.() -> Unit) { + logger.debug("Adding content for all positions") val c = ContentContext().apply(block) - applyToNodes(env.nodes, c) + contents.add(c) } fun inside(filter: PositionBasedFilter<*>, block: ContentContext.() -> Unit) { @Suppress("UNCHECKED_CAST") val filter = filter as PositionBasedFilter

- val c = ContentContext().apply(block) - applyToNodes( - env.nodes.filter { node -> - filter.contains(env.getPosition(node)) - }, - c, - ) + logger.debug("Adding content for positions inside filter: {}", filter) + val c = ContentContext(filter).apply(block) + contents.add(c) } - fun programs(block: ProgramsContext.() -> Unit) { - ProgramsContext().apply(block) + fun programs(block: ProgramsContext.() -> Unit) { + programsContext.apply(block) } - private fun applyToNodes(nodes: Collection>, content: ContentContext) { - nodes.forEach { node -> + + // meant to be used outside here + fun applyToNodes(node: Node, position: P, content: ContentContext) { + logger.debug("Applying node to nodes for position: {}, deployment {}", position, deployment) + if (content.filter == null || content.filter.contains(position)) { + logger.debug("Creating molecule for node at position: {}", position) val mol = inc.createMolecule( content.molecule ?: error("Molecule not specified"), ) + logger.debug("Creating concentration for molecule: {}", mol) val conc = inc.createConcentration(content.concentration) + logger.debug("Setting concentration for molecule: {} to node at position: {}", mol, position) node.setConcentration(mol, conc) } } - inner class ContentContext { + inner class ContentContext(val filter: PositionBasedFilter

? = null) { var molecule: String? = null var concentration: T? = null } - inner class ProgramsContext { - val programs: MutableList Unit> = mutableListOf() - fun all(block: ProgramContext.() -> Unit) { - programs.add(block) - applyToNodes(env.nodes, block) - } - fun inside(filter: PositionBasedFilter

, block: ProgramContext.() -> Unit) { - programs.add(block) - applyToNodes( - env.nodes.filter { node -> - filter.contains(env.getPosition(node)) - }, - block, - ) - } - - private fun applyToNodes(nodes: Collection>, program: ProgramContext.() -> Unit) { - nodes.forEach { node -> - val c = ProgramContext(node).apply(program) - val timeDistribution = c.timeDistribution - ?: inc.createTimeDistribution( - generator, - env, - node, - null, - ) - val r = when { - c.reaction != null -> { - // User provided a custom reaction object - c.reaction!! - } - else -> { - // Create a basic reaction with custom actions/conditions - inc.createReaction( - generator, - env, - node, - timeDistribution, - c.program, - ) - } - } - r.actions = r.actions + c.actions.map { it() } - r.conditions = r.conditions + c.conditions.map { it() } - node.addReaction(r) - } - } - inner class ProgramContext(val node: Node) { - var program: String? = null - var actions: Collection<() -> Action> = emptyList() - var conditions: Collection<() -> Condition> = emptyList() - var timeDistribution: TimeDistribution? = null - var reaction: Reaction? = null - fun timeDistribution(td: String) { - timeDistribution = inc.createTimeDistribution( - generator, - env, - node, - td, - ) - } - fun addAction(block: () -> Action) { - actions = actions + block - } - fun addCondition(block: () -> Condition) { - conditions = conditions + block - } - - @Suppress("UNCHECKED_CAST") - operator fun TimeDistribution<*>.unaryPlus(): TimeDistribution = this as TimeDistribution - } - } } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt new file mode 100644 index 0000000000..990b8dc73c --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger +import it.unibo.alchemist.model.Action +import it.unibo.alchemist.model.Condition +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.PositionBasedFilter +import it.unibo.alchemist.model.Reaction +import it.unibo.alchemist.model.TimeDistribution + +class ProgramsContext>(val ctx: DeploymentsContext) { + inner class ProgramEntry( + val filter: PositionBasedFilter

?, + val program: ProgramsContext.ProgramContext.() -> Unit, + ) + val programs: MutableList = mutableListOf() + fun all(block: ProgramContext.() -> Unit) { + logger.debug("Adding program for all nodes") + programs.add(ProgramEntry(null, block)) + } + fun inside(filter: PositionBasedFilter

, block: ProgramContext.() -> Unit) { + logger.debug("Adding program for nodes inside filter: {}", filter) + programs.add(ProgramEntry(filter, block)) + } + + fun applyToNodes(node: Node, position: P, program: ProgramContext.() -> Unit, filter: PositionBasedFilter

?) { + logger.debug("Applying program to node at position: {}", position) + val c = ProgramContext(node).apply(program) + if (filter != null && !filter.contains(position)) { + return + } + logger.debug("Creating time distribution for program") + val timeDistribution = c.timeDistribution + ?: ctx.ctx.incarnation.createTimeDistribution( + ctx.ctx.simulationGenerator, + ctx.ctx.environment, + node, + null, + ) + logger.debug("Creating reaction for program") + val r = when { + c.reaction != null -> { // User provided a custom reaction object + c.reaction!! + } + else -> { // Create a basic reaction with custom actions/conditions + ctx.ctx.incarnation.createReaction( + ctx.ctx.simulationGenerator, + ctx.ctx.environment, + node, + timeDistribution, + c.program, + ) + } + } + logger.debug("Adding actions to reaction") + r.actions = r.actions + c.actions.map { it() } + logger.debug("Adding conditions to reaction") + r.conditions = r.conditions + c.conditions.map { it() } + + logger.debug("Adding condition to reaction") + node.addReaction(r) + } + inner class ProgramContext(val node: Node) { + var program: String? = null + var actions: Collection<() -> Action> = emptyList() + var conditions: Collection<() -> Condition> = emptyList() + var timeDistribution: TimeDistribution? = null + var reaction: Reaction? = null + fun timeDistribution(td: String) { + timeDistribution = ctx.ctx.incarnation.createTimeDistribution( + ctx.ctx.simulationGenerator, + ctx.ctx.environment, + node, + td, + ) + } + fun addAction(block: () -> Action) { + actions = actions + block + } + fun addCondition(block: () -> Condition) { + conditions = conditions + block + } + + @Suppress("UNCHECKED_CAST") + operator fun TimeDistribution<*>.unaryPlus(): TimeDistribution = this as TimeDistribution + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 78222cb30e..bf63ce62da 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -11,13 +11,9 @@ package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.boundary.DependentVariable import it.unibo.alchemist.boundary.Launcher -import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.DslLoader -import it.unibo.alchemist.boundary.dsl.model.Incarnation as Inc import it.unibo.alchemist.boundary.launchers.DefaultLauncher import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GlobalReaction @@ -25,20 +21,21 @@ import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.SupportedIncarnations import it.unibo.alchemist.model.TerminationPredicate -import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.linkingrules.NoLinks -import it.unibo.alchemist.model.positions.Euclidean2DPosition import java.io.Serializable -import kotlin.jvm.optionals.getOrElse +import org.apache.commons.math3.random.MersenneTwister +import org.apache.commons.math3.random.RandomGenerator class SimulationContext>(val incarnation: Incarnation, val environment: Environment) { val buildSteps: MutableList<() -> Unit> = mutableListOf() val monitors: MutableList> = mutableListOf() val exporters: MutableList> = mutableListOf() var launcher: Launcher = DefaultLauncher() + var scenarioGenerator: RandomGenerator = MersenneTwister(0L) + var simulationGenerator: RandomGenerator = MersenneTwister(0L) + // deploymemt -> node -> program (time distribution -> actionable ( simulation)) private val layers: MutableMap> = HashMap() private var _networkModel: LinkingRule = NoLinks() var networkModel: LinkingRule @@ -90,31 +87,3 @@ class SimulationContext>(val incarnation: Incarnation, fun variable(source: () -> T): VariablesContext.DependentVariableProvider = variablesContext.dependent(source) } - -fun > createLoader(dsl: SimulationContext): Loader = object : DslLoader(dsl) { - override val constants: Map = emptyMap() // not needed - override val dependentVariables: Map> = emptyMap() // not needed - override val variables: Map> = dsl.variablesContext.variables - override val remoteDependencies: List = emptyList() // TODO: to implement - override val launcher: Launcher = dsl.launcher -} - -fun > Inc.incarnation(): Incarnation = SupportedIncarnations.get(this.name).getOrElse { - throw IllegalArgumentException("Incarnation $this not supported") -} - -fun > simulation( - incarnation: Incarnation, - environment: Environment, - block: SimulationContext.() -> Unit, -): Loader = createLoader(SimulationContext(incarnation, environment).apply(block)) - -fun > simulation( - incarnation: Incarnation, - block: SimulationContext.() -> Unit, -): Loader { - @Suppress("UNCHECKED_CAST") - val defaultEnv = Continuous2DEnvironment(incarnation as Incarnation) - val ctx = SimulationContext(incarnation, defaultEnv).apply(block) - return createLoader(ctx) -} From 995d89c00f8cf3c0b74bb967098a55ef4a9150fd Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 27 Oct 2025 17:07:00 +0100 Subject: [PATCH 018/196] refactor: refactor dsl structure --- .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 55 ++++++++++++++ .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 72 ++++++++++++++----- .../alchemist/dsl/SimulationsComparisons.kt | 5 ++ .../alchemist/dsl/StaticComparisonHelper.kt | 41 +++++++++++ .../it/unibo/alchemist/dsl/TestContents.kt | 4 +- .../it/unibo/alchemist/dsl/TestDeployments.kt | 4 +- .../it/unibo/alchemist/dsl/TestSimulations.kt | 10 +-- .../it/unibo/alchemist/dsl/TestVariables.kt | 4 +- .../src/test/resources/dsl/02-manynodes.yml | 6 +- .../test/resources/dsl/16-programsfilters.yml | 22 ++++++ 10 files changed, 191 insertions(+), 32 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt create mode 100644 alchemist-loading/src/test/resources/dsl/16-programsfilters.yml diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt new file mode 100644 index 0000000000..b498488f57 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl + +import it.unibo.alchemist.boundary.DependentVariable +import it.unibo.alchemist.boundary.Launcher +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.Variable +import it.unibo.alchemist.boundary.dsl.model.Incarnation as Inc +import it.unibo.alchemist.boundary.dsl.model.SimulationContext +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.SupportedIncarnations +import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.positions.Euclidean2DPosition +import kotlin.jvm.optionals.getOrElse + +object Dsl { + fun > createLoader(dsl: SimulationContext): Loader = object : DslLoader(dsl) { + override val constants: Map = emptyMap() // not needed + override val dependentVariables: Map> = emptyMap() // not needed + override val variables: Map> = dsl.variablesContext.variables + override val remoteDependencies: List = emptyList() // not needed + override val launcher: Launcher = dsl.launcher + } + + fun > Inc.incarnation(): Incarnation = + SupportedIncarnations.get(this.name).getOrElse { + throw IllegalArgumentException("Incarnation $this not supported") + } + + fun > simulation( + incarnation: Incarnation, + environment: Environment, + block: SimulationContext.() -> Unit, + ): Loader = createLoader(SimulationContext(incarnation, environment).apply(block)) + + fun > simulation( + incarnation: Incarnation, + block: SimulationContext.() -> Unit, + ): Loader { + @Suppress("UNCHECKED_CAST") + val defaultEnv = Continuous2DEnvironment(incarnation as Incarnation) + val ctx = SimulationContext(incarnation, defaultEnv).apply(block) + return createLoader(ctx) + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 62ee4cd172..a1724510de 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -13,10 +13,10 @@ package it.unibo.alchemist.dsl import another.location.SimpleMonitor import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.boundary.dsl.model.Incarnation.PROTELIS import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE -import it.unibo.alchemist.boundary.dsl.model.incarnation -import it.unibo.alchemist.boundary.dsl.model.simulation import it.unibo.alchemist.boundary.exporters.CSVExporter import it.unibo.alchemist.boundary.exportfilters.CommonFilters import it.unibo.alchemist.boundary.extractors.MoleculeReader @@ -55,28 +55,31 @@ object DslLoaderFunctions { } } } + fun > test02ManyNodes(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - networkModel = ConnectWithinDistance(5.0) + simulationGenerator = MersenneTwister(10L) + scenarioGenerator = MersenneTwister(20L) + networkModel = ConnectWithinDistance(0.5) deployments { - generator = MersenneTwister(10) - val circle = Circle( - environment, - generator, - 1000, - 0.0, - 0.0, - 10.0, + deploy( + Circle( + environment, + generator, + 10, + 0.0, + 0.0, + 10.0, + ), ) - deploy(circle) } } } fun > test03Grid(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - networkModel = ConnectWithinDistance(5.0) + networkModel = ConnectWithinDistance(0.5) deployments { val grid = Grid( environment, @@ -97,7 +100,7 @@ object DslLoaderFunctions { fun > test05Content(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - networkModel = ConnectWithinDistance(5.0) + networkModel = ConnectWithinDistance(0.5) deployments { val hello = "hello" deploy( @@ -120,7 +123,7 @@ object DslLoaderFunctions { fun > test06ContentFiltered(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - networkModel = ConnectWithinDistance(5.0) + networkModel = ConnectWithinDistance(0.5) deployments { val hello = "hello" deploy( @@ -144,11 +147,10 @@ object DslLoaderFunctions { } } - @Suppress("DEPRECATION") fun > test07Programs(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - networkModel = ConnectWithinDistance(5.0) + networkModel = ConnectWithinDistance(0.5) deployments { val token = "token" deploy( @@ -199,7 +201,7 @@ object DslLoaderFunctions { fun > test09TimeDistribution(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - networkModel = ConnectWithinDistance(5.0) + networkModel = ConnectWithinDistance(0.5) deployments { deploy( Grid( @@ -355,4 +357,38 @@ object DslLoaderFunctions { } } } + + @Suppress("DEPRECATION") + fun > test16ProgramsFilters(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + networkModel = ConnectWithinDistance(0.5) + deployments { + val token = "token" + deploy( + Grid( + environment, generator, + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { + molecule = token + } + programs { + inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { + timeDistribution("1") + program = "{token} --> {firing}" + } + all { + program = "{firing} --> +{token}" + } + } + } + } + } + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt index 31521f78e6..01f3d9e759 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt @@ -82,4 +82,9 @@ class SimulationsComparisons { fun > test15() { { DslLoaderFunctions.test15Variables() }.shouldEqual("dsl/15-variables.yml") } + + @Test + fun > test16() { + { DslLoaderFunctions.test16ProgramsFilters() }.shouldEqual("dsl/16-programsfilters.yml") + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt index 33f2fcd06d..daf6abca3c 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt @@ -126,6 +126,9 @@ object StaticComparisonHelper { "Linking rule types should match", ) + // Compare neighborhoods induced by the linking rule + compareNeighborhoods(dslEnv, yamlEnv) + // Compare programs (reactions) comparePrograms(dslEnv, yamlEnv) @@ -133,6 +136,44 @@ object StaticComparisonHelper { compareLayers(dslEnv, yamlEnv) } + /** + * Compares neighborhoods for each node matched by position in both environments + */ + private fun > compareNeighborhoods(dslEnv: Environment, yamlEnv: Environment) { + val dslByPos = dslEnv.nodes.associateBy { dslEnv.getPosition(it) } + val yamlByPos = yamlEnv.nodes.associateBy { yamlEnv.getPosition(it) } + + // Positions should already match; guard to provide clearer error if not + assertEquals( + yamlByPos.keys, + dslByPos.keys, + "Node position sets should match before neighborhood comparison", + ) + + for (position in dslByPos.keys) { + val dslNode = dslByPos.getValue(position) + val yamlNode = yamlByPos.getValue(position) + + val dslNeighborPositions = dslEnv + .getNeighborhood(dslNode) + .neighbors + .map { dslEnv.getPosition(it) } + .toSet() + + val yamlNeighborPositions = yamlEnv + .getNeighborhood(yamlNode) + .neighbors + .map { yamlEnv.getPosition(it) } + .toSet() + + assertEquals( + yamlNeighborPositions, + dslNeighborPositions, + "Neighborhood for node at $position should match", + ) + } + } + /** * Compares node contents (molecules and concentrations) */ diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt index d548ceab68..4c93058ed6 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -9,9 +9,9 @@ package it.unibo.alchemist.dsl +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE -import it.unibo.alchemist.boundary.dsl.model.incarnation -import it.unibo.alchemist.boundary.dsl.model.simulation import it.unibo.alchemist.model.deployments.Point import it.unibo.alchemist.model.positions.Euclidean2DPosition import org.junit.jupiter.api.Test diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index 75ed80e2f0..bd60949acb 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -9,9 +9,9 @@ package it.unibo.alchemist.dsl +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.boundary.dsl.model.Incarnation -import it.unibo.alchemist.boundary.dsl.model.incarnation -import it.unibo.alchemist.boundary.dsl.model.simulation import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point import it.unibo.alchemist.model.positions.Euclidean2DPosition diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt index 0be07fa348..eea4791b6a 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt @@ -9,9 +9,9 @@ package it.unibo.alchemist.dsl -import it.unibo.alchemist.boundary.dsl.model.Incarnation -import it.unibo.alchemist.boundary.dsl.model.incarnation -import it.unibo.alchemist.boundary.dsl.model.simulation +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation +import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.positions.Euclidean2DPosition import org.junit.jupiter.api.Test @@ -20,7 +20,7 @@ class TestSimulations { @Test fun testIncarnation() { - val incarnation = Incarnation.SAPERE.incarnation() + val incarnation = SAPERE.incarnation() val loader = simulation(incarnation) { } loader.launch(loader.launcher) @@ -28,7 +28,7 @@ class TestSimulations { @Test fun testLinkingRule() { - val incarnation = Incarnation.SAPERE.incarnation() + val incarnation = SAPERE.incarnation() val loader = simulation(incarnation) { networkModel = ConnectWithinDistance(5.0) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt index bed366f6ea..413092ada8 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -13,9 +13,9 @@ import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.booleans.shouldBeTrue import io.kotest.matchers.doubles.shouldBeExactly import io.kotest.matchers.shouldBe +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE -import it.unibo.alchemist.boundary.dsl.model.incarnation -import it.unibo.alchemist.boundary.dsl.model.simulation import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.model.Position diff --git a/alchemist-loading/src/test/resources/dsl/02-manynodes.yml b/alchemist-loading/src/test/resources/dsl/02-manynodes.yml index 581fa8aed1..e8e3a10ff2 100644 --- a/alchemist-loading/src/test/resources/dsl/02-manynodes.yml +++ b/alchemist-loading/src/test/resources/dsl/02-manynodes.yml @@ -1,8 +1,8 @@ incarnation: sapere seeds: - scenario: 10.0 - simulation: 10.0 + scenario: 20 + simulation: 10 network-model: type: ConnectWithinDistance @@ -10,4 +10,4 @@ network-model: deployments: type: Circle - parameters: [1000, 0, 0, 10] + parameters: [10, 0, 0, 10] diff --git a/alchemist-loading/src/test/resources/dsl/16-programsfilters.yml b/alchemist-loading/src/test/resources/dsl/16-programsfilters.yml new file mode 100644 index 0000000000..86e1159b7d --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/16-programsfilters.yml @@ -0,0 +1,22 @@ +incarnation: sapere + +network-model: + type: ConnectWithinDistance + parameters: [0.5] + +deployments: + type: Grid + parameters: [-5, -5, 5, 5, 0.25, 0.25, 0.1, 0.1] + contents: + in: + type: Rectangle + parameters: [-0.5, -0.5, 1, 1] + molecule: token + programs: + - time-distribution: 1 + in: + type: Rectangle + parameters: [ -0.5, -0.5, 1, 1 ] + program: > + {token} --> {firing} + - program: "{firing} --> +{token}" From b64f9df05397d39cace9d2a572ea878d44d55bc6 Mon Sep 17 00:00:00 2001 From: marco Date: Tue, 28 Oct 2025 10:36:20 +0100 Subject: [PATCH 019/196] feat: add support for custom nodes definition --- .../boundary/dsl/model/DeploymentsContext.kt | 31 +++++++++++++++---- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 29 +++++++++++++++-- .../alchemist/dsl/SimulationsComparisons.kt | 5 +++ .../alchemist/dsl/StaticComparisonHelper.kt | 8 +++++ .../src/test/resources/dsl/17-customnodes.yml | 7 +++++ 5 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 alchemist-loading/src/test/resources/dsl/17-customnodes.yml diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index 8f97d2658f..f18da29db0 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -15,6 +15,8 @@ import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter +import it.unibo.alchemist.model.linkingrules.CombinedLinkingRule +import it.unibo.alchemist.model.linkingrules.NoLinks class DeploymentsContext>(val ctx: SimulationContext) { val environment: Environment<*, *> = ctx.environment as Environment<*, *> @@ -36,15 +38,28 @@ class DeploymentsContext>(val ctx: SimulationContext) { } private fun populateDeployment(deploymentContext: DeploymentContext) { val deployment = deploymentContext.deployment + // Additional linking rules + deployment.getAssociatedLinkingRule()?.let { newLinkingRule -> + val composedLinkingRule = + when (val linkingRule = ctx.environment.linkingRule) { + is NoLinks -> newLinkingRule + is CombinedLinkingRule -> CombinedLinkingRule(linkingRule.subRules + listOf(newLinkingRule)) + else -> CombinedLinkingRule(listOf(linkingRule, newLinkingRule)) + } + ctx.environment.linkingRule = composedLinkingRule + } deployment.stream().forEach { position -> logger.debug("visiting position: {} for deployment: {}", position, deployment) logger.debug("creaing node for deployment: {}", deployment) - val node = inc.createNode( - ctx.simulationGenerator, - env, - null, - ) - // TODO: add support for custom nodes + val node = if (deploymentContext.nodeFactory == null) { + inc.createNode( + ctx.simulationGenerator, + env, + null, + ) + } else { + deploymentContext.nodeFactory!!.invoke() + } // TODO: load properties // load contents val contents = deploymentContext.contents @@ -68,6 +83,7 @@ class DeploymentsContext>(val ctx: SimulationContext) { inner class DeploymentContext(val deployment: Deployment

) { val contents: MutableList = mutableListOf() + var nodeFactory: (() -> Node)? = null val programsContext: ProgramsContext = ProgramsContext(this@DeploymentsContext) init { logger.debug("Visiting deployment: {}", deployment) @@ -87,6 +103,9 @@ class DeploymentsContext>(val ctx: SimulationContext) { fun programs(block: ProgramsContext.() -> Unit) { programsContext.apply(block) } + fun nodes(factory: () -> Node) { + nodeFactory = factory + } // meant to be used outside here fun applyToNodes(node: Node, position: P, content: ContentContext) { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index a1724510de..1610fcdb56 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -24,7 +24,9 @@ import it.unibo.alchemist.boundary.extractors.Time import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition +import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.deployments.Circle import it.unibo.alchemist.model.deployments.Grid @@ -34,6 +36,7 @@ import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.maps.actions.ReproduceGPSTrace import it.unibo.alchemist.model.maps.deployments.FromGPSTrace import it.unibo.alchemist.model.maps.environments.OSMEnvironment +import it.unibo.alchemist.model.nodes.TestNode import it.unibo.alchemist.model.positionfilters.Rectangle import it.unibo.alchemist.model.positions.Euclidean2DPosition import it.unibo.alchemist.model.reactions.Event @@ -59,8 +62,8 @@ object DslLoaderFunctions { fun > test02ManyNodes(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - simulationGenerator = MersenneTwister(10L) - scenarioGenerator = MersenneTwister(20L) + simulationGenerator = MersenneTwister(10) + scenarioGenerator = MersenneTwister(20) networkModel = ConnectWithinDistance(0.5) deployments { deploy( @@ -358,7 +361,6 @@ object DslLoaderFunctions { } } - @Suppress("DEPRECATION") fun > test16ProgramsFilters(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { @@ -391,4 +393,25 @@ object DslLoaderFunctions { } } } + fun > test17CustomNodes(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + deployments { + deploy( + Circle( + environment, + generator, + 10, + 0.0, + 0.0, + 5.0, + ), + ) { + nodes { + TestNode(env as Environment) as Node + } + } + } + } + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt index 01f3d9e759..4e81e33d70 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt @@ -87,4 +87,9 @@ class SimulationsComparisons { fun > test16() { { DslLoaderFunctions.test16ProgramsFilters() }.shouldEqual("dsl/16-programsfilters.yml") } + + @Test + fun > test17() { + { DslLoaderFunctions.test17CustomNodes() }.shouldEqual("dsl/17-customnodes.yml") + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt index daf6abca3c..491741cad8 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt @@ -106,6 +106,14 @@ object StaticComparisonHelper { dslEnv.nodes.size, "Node counts should match", ) + // compare nodes class names + val dslNodeTypes = dslEnv.nodes.map { it::class }.sortedBy { it.simpleName } + val yamlNodeTypes = yamlEnv.nodes.map { it::class }.sortedBy { it.simpleName } + assertEquals( + yamlNodeTypes, + dslNodeTypes, + "Node types should match", + ) // Compare node positions val dslPositions = dslEnv.nodes.map { dslEnv.getPosition(it) }.toSet() diff --git a/alchemist-loading/src/test/resources/dsl/17-customnodes.yml b/alchemist-loading/src/test/resources/dsl/17-customnodes.yml new file mode 100644 index 0000000000..1c5a5a3706 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/17-customnodes.yml @@ -0,0 +1,7 @@ +incarnation: sapere + +deployments: + type: Circle + parameters: [10, 0, 0, 5] + nodes: + type: it.unibo.alchemist.model.nodes.TestNode From 4cf330351b576da4f531b8aabec279ae0093733b Mon Sep 17 00:00:00 2001 From: marco Date: Tue, 28 Oct 2025 12:46:59 +0100 Subject: [PATCH 020/196] feat: add support for node properties --- .../boundary/dsl/model/DeploymentsContext.kt | 9 +++- .../boundary/dsl/model/PropertiesContext.kt | 50 +++++++++++++++++++ .../boundary/properties/TestNodeProperty.kt | 20 ++++++++ .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 29 +++++++++++ .../alchemist/dsl/SimulationsComparisons.kt | 5 ++ .../alchemist/dsl/StaticComparisonHelper.kt | 11 +++- .../src/test/resources/dsl/18-properties.yml | 18 +++++++ 7 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt create mode 100644 alchemist-loading/src/test/resources/dsl/18-properties.yml diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index f18da29db0..092277eddb 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -60,7 +60,8 @@ class DeploymentsContext>(val ctx: SimulationContext) { } else { deploymentContext.nodeFactory!!.invoke() } - // TODO: load properties + // load properties + deploymentContext.propertiesContext.applyToNode(node, position) // load contents val contents = deploymentContext.contents for (content in contents) { @@ -84,6 +85,7 @@ class DeploymentsContext>(val ctx: SimulationContext) { inner class DeploymentContext(val deployment: Deployment

) { val contents: MutableList = mutableListOf() var nodeFactory: (() -> Node)? = null + var propertiesContext: PropertiesContext = PropertiesContext() val programsContext: ProgramsContext = ProgramsContext(this@DeploymentsContext) init { logger.debug("Visiting deployment: {}", deployment) @@ -106,8 +108,11 @@ class DeploymentsContext>(val ctx: SimulationContext) { fun nodes(factory: () -> Node) { nodeFactory = factory } + fun properties(block: PropertiesContext.() -> Unit) { + propertiesContext.apply(block) + } - // meant to be used outside here + // meant to be called from outer class fun applyToNodes(node: Node, position: P, content: ContentContext) { logger.debug("Applying node to nodes for position: {}, deployment {}", position, deployment) if (content.filter == null || content.filter.contains(position)) { diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt new file mode 100644 index 0000000000..09f0d1513a --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.NodeProperty +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.PositionBasedFilter + +class PropertiesContext> { + val propertiesCtx: MutableList Unit, PositionBasedFilter

?>> = mutableListOf() + fun inside(filter: PositionBasedFilter<*>, block: PropertyContext.() -> Unit) { + @Suppress("UNCHECKED_CAST") + val filter = filter as PositionBasedFilter

+ propertiesCtx.add(block to filter) + logger.debug("Adding property for nodes inside filter: {}", filter) + } + fun all(block: PropertyContext.() -> Unit) { + propertiesCtx.add(block to null) + logger.debug("Adding property for all nodes") + } + fun applyToNode(node: Node, position: P) { + propertiesCtx.forEach { (propertyCtx, filter) -> + if (filter == null || filter.contains(position)) { + val properties = PropertyContext(filter, node) + .apply(propertyCtx) + .properties + properties.forEach { property -> + logger.debug("Applying property: {} to node: {}", property, node) + node.addProperty(property) + } + } + } + } + inner class PropertyContext(val filter: PositionBasedFilter

?, val node: Node) { + var properties: MutableList> = mutableListOf() + fun add(property: NodeProperty) { + logger.debug("Adding property: {}", property) + properties.add(property) + } + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt new file mode 100644 index 0000000000..1e8fe6f72c --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.properties + +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.NodeProperty +import it.unibo.alchemist.model.properties.AbstractNodeProperty + +class TestNodeProperty(node: Node, val s: String) : AbstractNodeProperty(node) { + override fun cloneOnNewNode(node: Node): NodeProperty = TestNodeProperty(node, s) + + override fun toString(): String = super.toString() + "($s)" +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 1610fcdb56..4b1dff7d01 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -21,6 +21,7 @@ import it.unibo.alchemist.boundary.exporters.CSVExporter import it.unibo.alchemist.boundary.exportfilters.CommonFilters import it.unibo.alchemist.boundary.extractors.MoleculeReader import it.unibo.alchemist.boundary.extractors.Time +import it.unibo.alchemist.boundary.properties.TestNodeProperty import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution @@ -414,4 +415,32 @@ object DslLoaderFunctions { } } } + fun > test18NodeProperties(): Loader { + val incarnation = SAPERE.incarnation() + return simulation(incarnation) { + deployments { + deploy( + Circle( + environment, + generator, + 1000, + 0.0, + 0.0, + 15.0, + ), + ) { + properties { + val filter = Rectangle(-3.0, -3.0, 2.0, 2.0) + val filter2 = Rectangle(3.0, 3.0, 2.0, 2.0) + inside(filter) { + add(TestNodeProperty(node, "a")) + } + inside(filter2) { + add(TestNodeProperty(node, "b")) + } + } + } + } + } + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt index 4e81e33d70..fdd6fed03c 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt @@ -92,4 +92,9 @@ class SimulationsComparisons { fun > test17() { { DslLoaderFunctions.test17CustomNodes() }.shouldEqual("dsl/17-customnodes.yml") } + + @Test + fun > test18() { + { DslLoaderFunctions.test18NodeProperties() }.shouldEqual("dsl/18-properties.yml") + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt index 491741cad8..cf84667d56 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt @@ -123,7 +123,16 @@ object StaticComparisonHelper { dslPositions, "Node positions should match", ) - + // compare node properties + val dslNodeProperties = dslEnv.nodes.flatMap { it.properties }.map { it.toString() }.sortedBy { it } + val yamlNodeProperties = yamlEnv.nodes.flatMap { it.properties }.map { it.toString() }.sortedBy { it } + println(dslNodeProperties) + println(yamlNodeProperties) + assertEquals( + yamlNodeProperties, + dslNodeProperties, + "Node properties should match", + ) // Compare node contents (molecules and concentrations) compareNodeContents(dslEnv, yamlEnv) diff --git a/alchemist-loading/src/test/resources/dsl/18-properties.yml b/alchemist-loading/src/test/resources/dsl/18-properties.yml new file mode 100644 index 0000000000..5bcb8f217f --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/18-properties.yml @@ -0,0 +1,18 @@ +incarnation: sapere + +deployments: + - type: Circle + parameters: [1000, 0, 0, 15] + properties: + - type: TestNodeProperty + parameters: ["a"] + in: + type: Rectangle + parameters: [-3, -3, 2, 2] + - type: TestNodeProperty + parameters: [ "b" ] + in: + type: Rectangle + parameters: [3, 3, 2, 2] + + From 1d69e8b4652771d890018082a6aa0f36cb8fa8e9 Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 8 Nov 2025 12:49:49 +0100 Subject: [PATCH 021/196] refactor: add code initial documentation --- .../boundary/dsl/model/DeploymentsContext.kt | 117 +++++++++++++-- .../boundary/dsl/model/ExporterContext.kt | 20 ++- .../boundary/dsl/model/ProgramsContext.kt | 137 ++++++++++++++---- .../boundary/dsl/model/PropertiesContext.kt | 62 ++++++-- .../boundary/dsl/model/SimulationContext.kt | 117 +++++++++++++-- .../boundary/dsl/model/VariablesContext.kt | 82 ++++++++++- 6 files changed, 461 insertions(+), 74 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index 092277eddb..d12e76968b 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -18,13 +18,36 @@ import it.unibo.alchemist.model.PositionBasedFilter import it.unibo.alchemist.model.linkingrules.CombinedLinkingRule import it.unibo.alchemist.model.linkingrules.NoLinks -class DeploymentsContext>(val ctx: SimulationContext) { +/** + * Context for managing deployments in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + * @param ctx The simulation context. + */ +open class DeploymentsContext>(val ctx: SimulationContext) { + /** + * The environment instance. + */ val environment: Environment<*, *> = ctx.environment as Environment<*, *> + + /** + * The environment instance. + */ val env = ctx.environment + + /** + * The scenario generator. + */ var generator = ctx.scenarioGenerator private val inc = ctx.incarnation - // deployment -> node -> molecule -> concentration -> program( timedistribution -> reaction + actions + conditions) + /** + * Deploys a deployment with a configuration block. + * + * @param deployment The deployment to configure. + * @param block The configuration block. + */ fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) { logger.debug("Deploying deployment: {}", deployment) @Suppress("UNCHECKED_CAST") @@ -32,6 +55,12 @@ class DeploymentsContext>(val ctx: SimulationContext) { // populate populateDeployment(d) } + + /** + * Deploys a deployment without additional configuration. + * + * @param deployment The deployment to deploy. + */ fun deploy(deployment: Deployment<*>) { @Suppress("UNCHECKED_CAST") this.deploy(deployment) {} @@ -51,15 +80,12 @@ class DeploymentsContext>(val ctx: SimulationContext) { deployment.stream().forEach { position -> logger.debug("visiting position: {} for deployment: {}", position, deployment) logger.debug("creaing node for deployment: {}", deployment) - val node = if (deploymentContext.nodeFactory == null) { - inc.createNode( + val node = deploymentContext.nodeFactory?.invoke() + ?: inc.createNode( ctx.simulationGenerator, env, null, ) - } else { - deploymentContext.nodeFactory!!.invoke() - } // load properties deploymentContext.propertiesContext.applyToNode(node, position) // load contents @@ -82,37 +108,94 @@ class DeploymentsContext>(val ctx: SimulationContext) { } } + /** + * Context for configuring a single deployment. + * + * @param deployment The deployment being configured. + */ inner class DeploymentContext(val deployment: Deployment

) { + /** + * The list of content contexts for this deployment. + */ val contents: MutableList = mutableListOf() + + /** + * Optional factory for creating custom nodes. + */ var nodeFactory: (() -> Node)? = null + + /** + * The properties context for this deployment. + */ var propertiesContext: PropertiesContext = PropertiesContext() + + /** + * The programs context for this deployment. + */ val programsContext: ProgramsContext = ProgramsContext(this@DeploymentsContext) init { logger.debug("Visiting deployment: {}", deployment) } + + /** + * Configures content for all positions in the deployment. + * + * @param block The content configuration block. + */ fun all(block: ContentContext.() -> Unit) { logger.debug("Adding content for all positions") val c = ContentContext().apply(block) contents.add(c) } + + /** + * Configures content for positions inside a filter. + * + * @param filter The position filter. + * @param block The content configuration block. + */ fun inside(filter: PositionBasedFilter<*>, block: ContentContext.() -> Unit) { @Suppress("UNCHECKED_CAST") - val filter = filter as PositionBasedFilter

- logger.debug("Adding content for positions inside filter: {}", filter) - val c = ContentContext(filter).apply(block) + val typedFilter = filter as PositionBasedFilter

+ logger.debug("Adding content for positions inside filter: {}", typedFilter) + val c = ContentContext(typedFilter).apply(block) contents.add(c) } + + /** + * Configures programs for this deployment. + * + * @param block The programs configuration block. + */ fun programs(block: ProgramsContext.() -> Unit) { programsContext.apply(block) } + + /** + * Sets a custom node factory for this deployment. + * + * @param factory The factory function for creating nodes. + */ fun nodes(factory: () -> Node) { nodeFactory = factory } + + /** + * Configures properties for this deployment. + * + * @param block The properties configuration block. + */ fun properties(block: PropertiesContext.() -> Unit) { propertiesContext.apply(block) } - // meant to be called from outer class + /** + * Applies content to nodes at a specific position. + * + * @param node The node to apply content to. + * @param position The position of the node. + * @param content The content context to apply. + */ fun applyToNodes(node: Node, position: P, content: ContentContext) { logger.debug("Applying node to nodes for position: {}, deployment {}", position, deployment) if (content.filter == null || content.filter.contains(position)) { @@ -128,8 +211,20 @@ class DeploymentsContext>(val ctx: SimulationContext) { } } + /** + * Context for configuring content (molecules and concentrations) for nodes. + * + * @param filter Optional position filter for applying content. + */ inner class ContentContext(val filter: PositionBasedFilter

? = null) { + /** + * The molecule name. + */ var molecule: String? = null + + /** + * The concentration value. + */ var concentration: T? = null } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt index 6b2b777f07..2c3fdce8ae 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt @@ -13,10 +13,28 @@ import it.unibo.alchemist.boundary.Exporter import it.unibo.alchemist.boundary.Extractor import it.unibo.alchemist.model.Position -class ExporterContext>(ctx: SimulationContext) { +/** + * Context for configuring exporters in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +class ExporterContext> { + /** + * The exporter type. + */ var type: Exporter? = null + + /** + * The list of data extractors. + */ var extractors: List> = emptyList() + /** + * Sets the data extractors for this exporter. + * + * @param extractors The extractors to use. + */ fun data(vararg extractors: Extractor<*>) { this.extractors = extractors.toList() } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt index 990b8dc73c..6e69c49683 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt @@ -1,12 +1,3 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger @@ -18,24 +9,62 @@ import it.unibo.alchemist.model.PositionBasedFilter import it.unibo.alchemist.model.Reaction import it.unibo.alchemist.model.TimeDistribution +/** + * Context for managing programs (reactions) in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + * @param ctx The deployments context. + */ class ProgramsContext>(val ctx: DeploymentsContext) { + /** + * Entry representing a program with its filter. + * + * @param filter Optional position filter. + * @param program The program configuration block. + */ inner class ProgramEntry( val filter: PositionBasedFilter

?, val program: ProgramsContext.ProgramContext.() -> Unit, ) + + /** + * List of program entries. + */ val programs: MutableList = mutableListOf() + + /** + * Configures a program for all nodes. + * + * @param block The program configuration block. + */ fun all(block: ProgramContext.() -> Unit) { logger.debug("Adding program for all nodes") programs.add(ProgramEntry(null, block)) } + + /** + * Configures a program for nodes inside a filter. + * + * @param filter The position filter. + * @param block The program configuration block. + */ fun inside(filter: PositionBasedFilter

, block: ProgramContext.() -> Unit) { logger.debug("Adding program for nodes inside filter: {}", filter) programs.add(ProgramEntry(filter, block)) } + /** + * Applies a program to nodes at a specific position. + * + * @param node The node to apply the program to. + * @param position The position of the node. + * @param program The program configuration block. + * @param filter Optional position filter. + */ fun applyToNodes(node: Node, position: P, program: ProgramContext.() -> Unit, filter: PositionBasedFilter

?) { logger.debug("Applying program to node at position: {}", position) - val c = ProgramContext(node).apply(program) + val c = ProgramContext(node, this).apply(program) if (filter != null && !filter.contains(position)) { return } @@ -48,49 +77,95 @@ class ProgramsContext>(val ctx: DeploymentsContext) { null, ) logger.debug("Creating reaction for program") - val r = when { - c.reaction != null -> { // User provided a custom reaction object - c.reaction!! - } - else -> { // Create a basic reaction with custom actions/conditions - ctx.ctx.incarnation.createReaction( - ctx.ctx.simulationGenerator, - ctx.ctx.environment, - node, - timeDistribution, - c.program, - ) - } + val r = c.reaction ?: run { + // Create a basic reaction with custom actions/conditions + ctx.ctx.incarnation.createReaction( + ctx.ctx.simulationGenerator, + ctx.ctx.environment, + node, + timeDistribution, + c.program, + ) } logger.debug("Adding actions to reaction") - r.actions = r.actions + c.actions.map { it() } + r.actions += c.actions.map { it() } logger.debug("Adding conditions to reaction") - r.conditions = r.conditions + c.conditions.map { it() } + r.conditions += c.conditions.map { it() } logger.debug("Adding condition to reaction") node.addReaction(r) } - inner class ProgramContext(val node: Node) { + + /** + * Context for configuring a single program (reaction). + * + * @param node The node this program is associated with. + * @param ctx The programs context. + */ + open inner class ProgramContext(val node: Node, val ctx: ProgramsContext) { + /** + * The program name. + */ var program: String? = null + + /** + * Collection of action factories. + */ var actions: Collection<() -> Action> = emptyList() + + /** + * Collection of condition factories. + */ var conditions: Collection<() -> Condition> = emptyList() + + /** + * The time distribution for the reaction. + */ var timeDistribution: TimeDistribution? = null + + /** + * Optional custom reaction instance. + */ var reaction: Reaction? = null + + /** + * Sets the time distribution using a string specification. + * + * @param td The time distribution specification. + */ fun timeDistribution(td: String) { - timeDistribution = ctx.ctx.incarnation.createTimeDistribution( - ctx.ctx.simulationGenerator, - ctx.ctx.environment, + timeDistribution = ctx.ctx.ctx.incarnation.createTimeDistribution( + ctx.ctx.ctx.simulationGenerator, + ctx.ctx.ctx.environment, node, td, ) } + + /** + * Adds an action to the program. + * + * @param block The action factory. + */ fun addAction(block: () -> Action) { - actions = actions + block + actions += block } + + /** + * Adds a condition to the program. + * + * @param block The condition factory. + */ fun addCondition(block: () -> Condition) { - conditions = conditions + block + conditions += block } + /** + * Unary plus operator for type casting time distributions. + * + * @param T The target type. + * @return The cast time distribution. + */ @Suppress("UNCHECKED_CAST") operator fun TimeDistribution<*>.unaryPlus(): TimeDistribution = this as TimeDistribution } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt index 09f0d1513a..72e36a63b2 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt @@ -1,12 +1,3 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger @@ -15,18 +6,47 @@ import it.unibo.alchemist.model.NodeProperty import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter +/** + * Context for managing node properties in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ class PropertiesContext> { + /** + * List of property contexts with their associated filters. + */ val propertiesCtx: MutableList Unit, PositionBasedFilter

?>> = mutableListOf() + + /** + * Configures properties for nodes inside a position filter. + * + * @param filter The position filter. + * @param block The property configuration block. + */ fun inside(filter: PositionBasedFilter<*>, block: PropertyContext.() -> Unit) { @Suppress("UNCHECKED_CAST") - val filter = filter as PositionBasedFilter

- propertiesCtx.add(block to filter) - logger.debug("Adding property for nodes inside filter: {}", filter) + val typedFilter = filter as PositionBasedFilter

+ propertiesCtx.add(block to typedFilter) + logger.debug("Adding property for nodes inside filter: {}", typedFilter) } + + /** + * Configures properties for all nodes. + * + * @param block The property configuration block. + */ fun all(block: PropertyContext.() -> Unit) { propertiesCtx.add(block to null) logger.debug("Adding property for all nodes") } + + /** + * Applies configured properties to a node at a specific position. + * + * @param node The node to apply properties to. + * @param position The position of the node. + */ fun applyToNode(node: Node, position: P) { propertiesCtx.forEach { (propertyCtx, filter) -> if (filter == null || filter.contains(position)) { @@ -40,8 +60,24 @@ class PropertiesContext> { } } } + + /** + * Context for configuring properties for a specific node. + * + * @param filter Optional position filter. + * @param node The node to configure properties for. + */ inner class PropertyContext(val filter: PositionBasedFilter

?, val node: Node) { - var properties: MutableList> = mutableListOf() + /** + * List of properties to add to the node. + */ + val properties: MutableList> = mutableListOf() + + /** + * Adds a property to the node. + * + * @param property The property to add. + */ fun add(property: NodeProperty) { logger.debug("Adding property: {}", property) properties.add(property) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index bf63ce62da..9ee9c3c455 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -27,63 +27,160 @@ import java.io.Serializable import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator +/** + * Main context for building and configuring a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + * @param incarnation The incarnation instance. + * @param environment The environment instance. + */ class SimulationContext>(val incarnation: Incarnation, val environment: Environment) { + /** + * List of build steps to execute. + */ val buildSteps: MutableList<() -> Unit> = mutableListOf() + + /** + * List of output monitors. + */ val monitors: MutableList> = mutableListOf() + + /** + * List of exporters. + */ val exporters: MutableList> = mutableListOf() + + /** + * The launcher for the simulation. + */ var launcher: Launcher = DefaultLauncher() + + /** + * The random generator for scenario generation. + */ var scenarioGenerator: RandomGenerator = MersenneTwister(0L) + + /** + * The random generator for simulation execution. + */ var simulationGenerator: RandomGenerator = MersenneTwister(0L) - // deploymemt -> node -> program (time distribution -> actionable ( simulation)) private val layers: MutableMap> = HashMap() private var _networkModel: LinkingRule = NoLinks() + + /** + * The network model (linking rule) for the environment. + */ var networkModel: LinkingRule get() = _networkModel set(value) { _networkModel = value environment.linkingRule = value } + + /** + * The variables context for managing simulation variables. + */ val variablesContext = VariablesContext() + + /** + * Executes all build steps. + */ fun build() { buildSteps.forEach { it() } } + /** + * Configures deployments for the simulation. + * + * @param block The deployments configuration block. + */ fun deployments(block: DeploymentsContext.() -> Unit) { buildSteps.add { DeploymentsContext(this).apply(block) } } + + /** + * Adds a termination predicate to the simulation. + * + * @param predicate The termination predicate. + */ fun addTerminator(predicate: TerminationPredicate<*, *>) { @Suppress("UNCHECKED_CAST") buildSteps.add { environment.addTerminator(predicate as TerminationPredicate) } } + + /** + * Adds an output monitor to the simulation. + * + * @param monitor The output monitor. + */ fun addMonitor(monitor: OutputMonitor) { buildSteps.add { monitors.add(monitor) } } + + /** + * Configures an exporter for the simulation. + * + * @param block The exporter configuration block. + */ fun exporter(block: ExporterContext.() -> Unit) { - buildSteps.add { exporters.add(ExporterContext(this).apply(block)) } + buildSteps.add { exporters.add(ExporterContext().apply(block)) } } + + /** + * Adds a global reaction to the simulation. + * + * @param program The global reaction. + */ fun program(program: GlobalReaction) { buildSteps.add { this.environment.addGlobalReaction(program) } } + + /** + * Schedules a block to run later during build. + * + * @param block The block to execute. + */ fun runLater(block: () -> Unit) { buildSteps.add { block() } } + + /** + * Configures a layer for the simulation. + * + * @param block The layer configuration block. + */ fun layer(block: LayerContext.() -> Unit) { buildSteps.add { - val l = LayerContext(this).apply(block) - require(l.layer != null) { "Layer must be specified" } - require(l.molecule != null) { "Molecule must be specified" } - require(!this.layers.containsKey(l.molecule)) { - "Inconsistent layer definition for molecule ${l.molecule}. " + + val l = LayerContext().apply(block) + val layer = requireNotNull(l.layer) { "Layer must be specified" } + val moleculeName = requireNotNull(l.molecule) { "Molecule must be specified" } + require(!this.layers.containsKey(moleculeName)) { + "Inconsistent layer definition for molecule $moleculeName. " + "There must be a single layer per molecule" } - val molecule = incarnation.createMolecule(l.molecule) - layers[l.molecule!!] = l.layer!! - environment.addLayer(molecule, l.layer!!) + val molecule = incarnation.createMolecule(moleculeName) + layers[moleculeName] = layer + environment.addLayer(molecule, layer) } } + + /** + * Registers a variable in the variables context. + * + * @param source The variable source. + * @return A variable provider for property delegation. + */ fun variable(source: Variable): VariablesContext.VariableProvider = variablesContext.register(source) + + /** + * Registers a dependent variable in the variables context. + * + * @param source The function that provides the variable value. + * @return A dependent variable provider for property delegation. + */ fun variable(source: () -> T): VariablesContext.DependentVariableProvider = variablesContext.dependent(source) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt index 240bb4e602..75d00a3aee 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt @@ -15,33 +15,94 @@ import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty +/** + * Context for managing variables in a simulation. + */ class VariablesContext { + /** + * Map of variable references. + */ val references: MutableMap = mutableMapOf() + + /** + * Map of registered variables. + */ val variables: MutableMap> = mutableMapOf() + + /** + * Map of dependent variables. + */ val dependentVariables: MutableMap Any> = mutableMapOf() + /** + * Registers a variable provider. + * + * @param source The variable source. + * @return A variable provider. + */ fun register(source: Variable): VariableProvider = VariableProvider(source) + + /** + * Registers a dependent variable provider. + * + * @param source The dependent variable source function. + * @return A dependent variable provider. + */ fun dependent(source: () -> T): DependentVariableProvider = DependentVariableProvider(source) + /** + * Provider for dependent variables that are computed from a source function. + * + * @param T The type of the variable value. + * @param source The function that provides the variable value. + */ inner class DependentVariableProvider(private val source: () -> T) { + /** + * Provides a delegate for property delegation. + * + * @param thisRef The receiver object. + * @param prop The property metadata. + * @return A read-only property delegate. + */ operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty { - if (variables.containsKey(prop.name) || dependentVariables.contains(prop.name)) { - throw IllegalStateException("Variable ${prop.name} already exists") + check(!variables.containsKey(prop.name) && !dependentVariables.contains(prop.name)) { + "Variable ${prop.name} already exists" } dependentVariables.put(prop.name, source) return DependentRef(source) } } + + /** + * Read-only property delegate for dependent variables. + * + * @param T The type of the variable value. + * @param source The function that provides the variable value. + */ inner class DependentRef(private val source: () -> T) : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): T = source() override fun setValue(thisRef: Any?, property: KProperty<*>, value: T): Unit = - throw IllegalStateException("Not allowed to assign a value to the variable ${property.name}") + error("Not allowed to assign a value to the variable ${property.name}") } + + /** + * Provider for variables that are registered with a Variable source. + * + * @param T The type of the variable value. + * @param source The variable source. + */ inner class VariableProvider(private val source: Variable<*>) { + /** + * Provides a delegate for property delegation. + * + * @param thisRef The receiver object. + * @param prop The property metadata. + * @return A read-only property delegate. + */ operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty { - if (variables.containsKey(prop.name) || dependentVariables.contains(prop.name)) { - throw IllegalStateException("Variable ${prop.name} already exists") + check(!variables.containsKey(prop.name) && !dependentVariables.contains(prop.name)) { + "Variable ${prop.name} already exists" } variables[prop.name] = source references[prop.name] = source.default @@ -49,16 +110,21 @@ class VariablesContext { } } + /** + * Read-write property delegate for variables. + * + * @param T The type of the variable value. + */ inner class Ref : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): T { - if (!references.contains(property.name)) { - throw IllegalStateException("Variable ${property.name} has no defined value") + check(references.contains(property.name)) { + "Variable ${property.name} has no defined value" } @Suppress("UNCHECKED_CAST") return references[property.name] as T } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T): Unit = - throw IllegalStateException("Not allowed to assign a value to the variable ${property.name}") + error("Not allowed to assign a value to the variable ${property.name}") } } From a27650aebb62738e5e2f13ad5615a71e2d6fc8d3 Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 8 Nov 2025 13:33:50 +0100 Subject: [PATCH 022/196] refactor: move yml test files --- alchemist-loading/src/test/resources/dsl/{ => yml}/01-nodes.yml | 0 .../src/test/resources/dsl/{ => yml}/02-manynodes.yml | 0 alchemist-loading/src/test/resources/dsl/{ => yml}/03-grid.yml | 0 alchemist-loading/src/test/resources/dsl/{ => yml}/05-content.yml | 0 alchemist-loading/src/test/resources/dsl/{ => yml}/06-filters.yml | 0 alchemist-loading/src/test/resources/dsl/{ => yml}/07-program.yml | 0 .../src/test/resources/dsl/{ => yml}/08-protelisprogram.yml | 0 .../src/test/resources/dsl/{ => yml}/09-timedistribution.yml | 0 .../src/test/resources/dsl/{ => yml}/10-environment.yml | 0 .../src/test/resources/dsl/{ => yml}/11-monitors.yml | 0 alchemist-loading/src/test/resources/dsl/{ => yml}/12-layers.yml | 0 .../src/test/resources/dsl/{ => yml}/13-globalreaction.yml | 0 .../src/test/resources/dsl/{ => yml}/14-exporters.yml | 0 .../src/test/resources/dsl/{ => yml}/15-variables.yml | 0 .../src/test/resources/dsl/{ => yml}/16-programsfilters.yml | 0 .../src/test/resources/dsl/{ => yml}/17-customnodes.yml | 0 .../src/test/resources/dsl/{ => yml}/18-properties.yml | 0 17 files changed, 0 insertions(+), 0 deletions(-) rename alchemist-loading/src/test/resources/dsl/{ => yml}/01-nodes.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/02-manynodes.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/03-grid.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/05-content.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/06-filters.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/07-program.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/08-protelisprogram.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/09-timedistribution.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/10-environment.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/11-monitors.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/12-layers.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/13-globalreaction.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/14-exporters.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/15-variables.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/16-programsfilters.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/17-customnodes.yml (100%) rename alchemist-loading/src/test/resources/dsl/{ => yml}/18-properties.yml (100%) diff --git a/alchemist-loading/src/test/resources/dsl/01-nodes.yml b/alchemist-loading/src/test/resources/dsl/yml/01-nodes.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/01-nodes.yml rename to alchemist-loading/src/test/resources/dsl/yml/01-nodes.yml diff --git a/alchemist-loading/src/test/resources/dsl/02-manynodes.yml b/alchemist-loading/src/test/resources/dsl/yml/02-manynodes.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/02-manynodes.yml rename to alchemist-loading/src/test/resources/dsl/yml/02-manynodes.yml diff --git a/alchemist-loading/src/test/resources/dsl/03-grid.yml b/alchemist-loading/src/test/resources/dsl/yml/03-grid.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/03-grid.yml rename to alchemist-loading/src/test/resources/dsl/yml/03-grid.yml diff --git a/alchemist-loading/src/test/resources/dsl/05-content.yml b/alchemist-loading/src/test/resources/dsl/yml/05-content.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/05-content.yml rename to alchemist-loading/src/test/resources/dsl/yml/05-content.yml diff --git a/alchemist-loading/src/test/resources/dsl/06-filters.yml b/alchemist-loading/src/test/resources/dsl/yml/06-filters.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/06-filters.yml rename to alchemist-loading/src/test/resources/dsl/yml/06-filters.yml diff --git a/alchemist-loading/src/test/resources/dsl/07-program.yml b/alchemist-loading/src/test/resources/dsl/yml/07-program.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/07-program.yml rename to alchemist-loading/src/test/resources/dsl/yml/07-program.yml diff --git a/alchemist-loading/src/test/resources/dsl/08-protelisprogram.yml b/alchemist-loading/src/test/resources/dsl/yml/08-protelisprogram.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/08-protelisprogram.yml rename to alchemist-loading/src/test/resources/dsl/yml/08-protelisprogram.yml diff --git a/alchemist-loading/src/test/resources/dsl/09-timedistribution.yml b/alchemist-loading/src/test/resources/dsl/yml/09-timedistribution.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/09-timedistribution.yml rename to alchemist-loading/src/test/resources/dsl/yml/09-timedistribution.yml diff --git a/alchemist-loading/src/test/resources/dsl/10-environment.yml b/alchemist-loading/src/test/resources/dsl/yml/10-environment.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/10-environment.yml rename to alchemist-loading/src/test/resources/dsl/yml/10-environment.yml diff --git a/alchemist-loading/src/test/resources/dsl/11-monitors.yml b/alchemist-loading/src/test/resources/dsl/yml/11-monitors.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/11-monitors.yml rename to alchemist-loading/src/test/resources/dsl/yml/11-monitors.yml diff --git a/alchemist-loading/src/test/resources/dsl/12-layers.yml b/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/12-layers.yml rename to alchemist-loading/src/test/resources/dsl/yml/12-layers.yml diff --git a/alchemist-loading/src/test/resources/dsl/13-globalreaction.yml b/alchemist-loading/src/test/resources/dsl/yml/13-globalreaction.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/13-globalreaction.yml rename to alchemist-loading/src/test/resources/dsl/yml/13-globalreaction.yml diff --git a/alchemist-loading/src/test/resources/dsl/14-exporters.yml b/alchemist-loading/src/test/resources/dsl/yml/14-exporters.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/14-exporters.yml rename to alchemist-loading/src/test/resources/dsl/yml/14-exporters.yml diff --git a/alchemist-loading/src/test/resources/dsl/15-variables.yml b/alchemist-loading/src/test/resources/dsl/yml/15-variables.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/15-variables.yml rename to alchemist-loading/src/test/resources/dsl/yml/15-variables.yml diff --git a/alchemist-loading/src/test/resources/dsl/16-programsfilters.yml b/alchemist-loading/src/test/resources/dsl/yml/16-programsfilters.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/16-programsfilters.yml rename to alchemist-loading/src/test/resources/dsl/yml/16-programsfilters.yml diff --git a/alchemist-loading/src/test/resources/dsl/17-customnodes.yml b/alchemist-loading/src/test/resources/dsl/yml/17-customnodes.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/17-customnodes.yml rename to alchemist-loading/src/test/resources/dsl/yml/17-customnodes.yml diff --git a/alchemist-loading/src/test/resources/dsl/18-properties.yml b/alchemist-loading/src/test/resources/dsl/yml/18-properties.yml similarity index 100% rename from alchemist-loading/src/test/resources/dsl/18-properties.yml rename to alchemist-loading/src/test/resources/dsl/yml/18-properties.yml From 16f38f2315f8b114a1f3d5925fe54d00903af098 Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 8 Nov 2025 13:38:26 +0100 Subject: [PATCH 023/196] refactor: add doc and better testing --- .../boundary/dsl/model/Incarnation.kt | 19 +++ .../alchemist/dsl/LayerComparisonUtils.kt | 45 +++++++ .../alchemist/dsl/RuntimeComparisonHelper.kt | 68 ++--------- .../alchemist/dsl/SimulationsComparisons.kt | 34 +++--- .../alchemist/dsl/StaticComparisonHelper.kt | 112 +++++------------- .../it/unibo/alchemist/dsl/TestComparators.kt | 44 +++++-- 6 files changed, 153 insertions(+), 169 deletions(-) create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt index 927558687e..c8ab733905 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt @@ -8,9 +8,28 @@ */ package it.unibo.alchemist.boundary.dsl.model + +/** + * Enumeration of available Alchemist incarnations. + */ enum class Incarnation { + /** + * SAPERE incarnation. + */ SAPERE, + + /** + * PROTELIS incarnation. + */ PROTELIS, + + /** + * SCAFI incarnation. + */ SCAFI, + + /** + * BIOCHEMISTRY incarnation. + */ BIOCHEMISTRY, } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt new file mode 100644 index 0000000000..180306ede1 --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt @@ -0,0 +1,45 @@ +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Position +import org.junit.jupiter.api.Assertions.assertEquals + +object LayerComparisonUtils { + fun > compareLayerValues(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing layer values...") + + val samplePositions = mutableListOf

() + + samplePositions.addAll(dslEnv.nodes.map { dslEnv.getPosition(it) }) + samplePositions.addAll(yamlEnv.nodes.map { yamlEnv.getPosition(it) }) + + val uniquePositions = samplePositions.distinct() + + if (uniquePositions.isNotEmpty()) { + for (position in uniquePositions) { + val dslLayerValues = dslEnv.layers.map { (it.getValue(position)) } + val yamlLayerValues = yamlEnv.layers.map { it.getValue(position) } + val dslDoubleValues = dslLayerValues.map { value -> + when (value) { + is Number -> value.toDouble() + else -> value.toString().toDoubleOrNull() ?: 0.0 + } + } + val yamlDoubleValues = yamlLayerValues.map { value -> + when (value) { + is Number -> value.toDouble() + else -> value.toString().toDoubleOrNull() ?: 0.0 + } + } + + assertEquals( + dslDoubleValues, + yamlDoubleValues, + "Layer values at position $position should match", + ) + } + } else { + println("Skipping layer value comparison - no valid positions found") + } + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt index 1c6bc9aade..05e3d230b7 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt @@ -30,7 +30,7 @@ object RuntimeComparisonHelper { /** * Compares loaders by running both simulations for a specified number of steps - * and comparing their final states + * and comparing their final states. */ fun > compareLoaders(dslLoader: Loader, yamlLoader: Loader, steps: Long = 1000L) { println("Running simulations for comparison...") @@ -68,7 +68,7 @@ object RuntimeComparisonHelper { } /** - * Adds step-based terminator to a simulation + * Adds step-based terminator to a simulation. */ private fun > addStepTerminator(simulation: Simulation, steps: Long) { // Add step-based terminator @@ -76,7 +76,7 @@ object RuntimeComparisonHelper { } /** - * Runs a simulation synchronously (terminator will stop it) + * Runs a simulation synchronously (terminator will stop it). */ private fun > runSimulationSynchronously(simulation: Simulation) { simulation.play() // Start the simulation @@ -85,7 +85,7 @@ object RuntimeComparisonHelper { } /** - * Compares the final states of two simulations after runtime execution + * Compares the final states of two simulations after runtime execution. */ private fun > compareRuntimeStates( dslSimulation: Simulation, @@ -104,7 +104,7 @@ object RuntimeComparisonHelper { } /** - * Compares simulation execution state (time, step, status, errors) + * Compares simulation execution state (time, step, status, errors). */ private fun > compareSimulationExecutionState( dslSimulation: Simulation, @@ -153,7 +153,7 @@ object RuntimeComparisonHelper { } /** - * Compares environment states after runtime execution + * Compares environment states after runtime execution. */ private fun > compareRuntimeEnvironmentStates( dslEnv: Environment, @@ -185,7 +185,7 @@ object RuntimeComparisonHelper { } /** - * Compares node states after runtime execution using position-based matching + * Compares node states after runtime execution using position-based matching. */ private fun > compareRuntimeNodeStates(dslEnv: Environment, yamlEnv: Environment) { println("Comparing runtime node states...") @@ -220,7 +220,7 @@ object RuntimeComparisonHelper { } /** - * Compares contents of two nodes at the same position + * Compares contents of two nodes at the same position. */ private fun compareNodeContentsAtPosition(dslNode: Node, yamlNode: Node, position: Any) { // Compare molecule counts @@ -271,7 +271,7 @@ object RuntimeComparisonHelper { } /** - * Compares global reactions after runtime execution + * Compares global reactions after runtime execution. */ private fun > compareRuntimeGlobalReactions( dslEnv: Environment, @@ -297,7 +297,7 @@ object RuntimeComparisonHelper { } /** - * Compares layers after runtime execution + * Compares layers after runtime execution. */ private fun > compareRuntimeLayers(dslEnv: Environment, yamlEnv: Environment) { println("Comparing runtime layers...") @@ -318,52 +318,6 @@ object RuntimeComparisonHelper { "Layer types should match after runtime", ) - // Compare layer values at sample positions - compareLayerValues(dslEnv, yamlEnv) - } - - /** - * Compares layer values at sample positions - */ - private fun > compareLayerValues(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing layer values...") - - // Sample positions to test layer values - val samplePositions = mutableListOf

() - - // Add positions from both environments' nodes - samplePositions.addAll(dslEnv.nodes.map { dslEnv.getPosition(it) }) - samplePositions.addAll(yamlEnv.nodes.map { yamlEnv.getPosition(it) }) - - // Remove duplicates - val uniquePositions = samplePositions.distinct() - - if (uniquePositions.isNotEmpty()) { - for (position in uniquePositions) { - val dslLayerValues = dslEnv.layers.map { (it.getValue(position)) } - val yamlLayerValues = yamlEnv.layers.map { it.getValue(position) } - // Convert all values to Double for comparison to handle Int vs Double differences - val dslDoubleValues = dslLayerValues.map { value -> - when (value) { - is Number -> value.toDouble() - else -> value.toString().toDoubleOrNull() ?: 0.0 - } - } - val yamlDoubleValues = yamlLayerValues.map { value -> - when (value) { - is Number -> value.toDouble() - else -> value.toString().toDoubleOrNull() ?: 0.0 - } - } - - assertEquals( - dslDoubleValues, - yamlDoubleValues, - "Layer values at position $position should match", - ) - } - } else { - println("Skipping layer value comparison - no valid positions found") - } + LayerComparisonUtils.compareLayerValues(dslEnv, yamlEnv) } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt index fdd6fed03c..9cee90eafd 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt @@ -15,86 +15,86 @@ class SimulationsComparisons { @Test fun > test01() { - { DslLoaderFunctions.test01Nodes() }.shouldEqual("dsl/01-nodes.yml") + { DslLoaderFunctions.test01Nodes() }.shouldEqual("dsl/yml/01-nodes.yml") } @Test fun > test02() { - { DslLoaderFunctions.test02ManyNodes() }.shouldEqual("dsl/02-manynodes.yml") + { DslLoaderFunctions.test02ManyNodes() }.shouldEqual("dsl/yml/02-manynodes.yml") } @Test fun > test03() { - { DslLoaderFunctions.test03Grid() }.shouldEqual("dsl/03-grid.yml") + { DslLoaderFunctions.test03Grid() }.shouldEqual("dsl/yml/03-grid.yml") } @Test fun > test05() { - { DslLoaderFunctions.test05Content() }.shouldEqual("dsl/05-content.yml") + { DslLoaderFunctions.test05Content() }.shouldEqual("dsl/yml/05-content.yml") } @Test fun > test06() { - { DslLoaderFunctions.test06ContentFiltered() }.shouldEqual("dsl/06-filters.yml") + { DslLoaderFunctions.test06ContentFiltered() }.shouldEqual("dsl/yml/06-filters.yml") } @Test fun > test07() { - { DslLoaderFunctions.test07Programs() }.shouldEqual("dsl/07-program.yml") + { DslLoaderFunctions.test07Programs() }.shouldEqual("dsl/yml/07-program.yml") } @Test fun > test08() { - DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/08-protelisprogram.yml") + DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/yml/08-protelisprogram.yml") } @Test fun > test09() { - { DslLoaderFunctions.test09TimeDistribution() }.shouldEqual("dsl/09-timedistribution.yml") + { DslLoaderFunctions.test09TimeDistribution() }.shouldEqual("dsl/yml/09-timedistribution.yml") } @Test fun > test10() { - { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/10-environment.yml") + { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/yml/10-environment.yml") } @Test fun > test11() { - { DslLoaderFunctions.test11monitors() }.shouldEqual("dsl/11-monitors.yml") + { DslLoaderFunctions.test11monitors() }.shouldEqual("dsl/yml/11-monitors.yml") } @Test fun > test12() { - { DslLoaderFunctions.test12Layers() }.shouldEqual("dsl/12-layers.yml") + { DslLoaderFunctions.test12Layers() }.shouldEqual("dsl/yml/12-layers.yml") } @Test fun > test13() { - { DslLoaderFunctions.test13GlobalReaction() }.shouldEqual("dsl/13-globalreaction.yml") + { DslLoaderFunctions.test13GlobalReaction() }.shouldEqual("dsl/yml/13-globalreaction.yml") } @Test fun > test14() { - { DslLoaderFunctions.test14Exporters() }.shouldEqual("dsl/14-exporters.yml") + { DslLoaderFunctions.test14Exporters() }.shouldEqual("dsl/yml/14-exporters.yml") } @Test fun > test15() { - { DslLoaderFunctions.test15Variables() }.shouldEqual("dsl/15-variables.yml") + { DslLoaderFunctions.test15Variables() }.shouldEqual("dsl/yml/15-variables.yml") } @Test fun > test16() { - { DslLoaderFunctions.test16ProgramsFilters() }.shouldEqual("dsl/16-programsfilters.yml") + { DslLoaderFunctions.test16ProgramsFilters() }.shouldEqual("dsl/yml/16-programsfilters.yml") } @Test fun > test17() { - { DslLoaderFunctions.test17CustomNodes() }.shouldEqual("dsl/17-customnodes.yml") + { DslLoaderFunctions.test17CustomNodes() }.shouldEqual("dsl/yml/17-customnodes.yml") } @Test fun > test18() { - { DslLoaderFunctions.test18NodeProperties() }.shouldEqual("dsl/18-properties.yml") + { DslLoaderFunctions.test18NodeProperties() }.shouldEqual("dsl/yml/18-properties.yml") } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt index cf84667d56..363277aa96 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt @@ -26,7 +26,7 @@ import org.junit.jupiter.api.Assertions.assertEquals object StaticComparisonHelper { /** - * Compares basic loader properties + * Compares basic loader properties. */ fun compareBasicProperties(dslLoader: Loader, yamlLoader: Loader) { println("Comparing basic properties...") @@ -79,7 +79,7 @@ object StaticComparisonHelper { } /** - * Compares the simulations generated by both loaders + * Compares the simulations generated by both loaders. */ fun > compareSimulations(dslLoader: Loader, yamlLoader: Loader) { println("Comparing simulations...") @@ -95,7 +95,7 @@ object StaticComparisonHelper { } /** - * Compares two environments + * Compares two environments. */ private fun > compareEnvironments(dslEnv: Environment, yamlEnv: Environment) { println("Comparing environments...") @@ -154,7 +154,7 @@ object StaticComparisonHelper { } /** - * Compares neighborhoods for each node matched by position in both environments + * Compares neighborhoods for each node matched by position in both environments. */ private fun > compareNeighborhoods(dslEnv: Environment, yamlEnv: Environment) { val dslByPos = dslEnv.nodes.associateBy { dslEnv.getPosition(it) } @@ -192,7 +192,7 @@ object StaticComparisonHelper { } /** - * Compares node contents (molecules and concentrations) + * Compares node contents (molecules and concentrations). */ private fun > compareNodeContents(dslEnv: Environment, yamlEnv: Environment) { println("Comparing node contents...") @@ -223,7 +223,7 @@ object StaticComparisonHelper { } /** - * Compares programs between environments + * Compares programs between environments. */ private fun > comparePrograms(dslEnv: Environment, yamlEnv: Environment) { println("Comparing programs...") @@ -236,7 +236,7 @@ object StaticComparisonHelper { } /** - * Compares global reactions + * Compares global reactions. */ private fun > compareGlobalReactions(dslEnv: Environment, yamlEnv: Environment) { println("Comparing global reactions...") @@ -262,7 +262,7 @@ object StaticComparisonHelper { } /** - * Compares node reactions (programs) + * Compares node reactions (programs). */ private fun > compareNodeReactions(dslEnv: Environment, yamlEnv: Environment) { println("Comparing node reactions...") @@ -295,7 +295,7 @@ object StaticComparisonHelper { } /** - * Compares reaction programs by comparing their string representations and dependencies + * Compares reaction programs by comparing their string representations and dependencies. */ private fun compareReactionPrograms(dslNodes: List>, yamlNodes: List>) { println("Comparing reaction programs...") @@ -310,30 +310,8 @@ object StaticComparisonHelper { "Total reactions count should match", ) - // Compare reactions by their string representations and dependencies - val dslReactions = dslNodes.flatMap { it.reactions }.map { reaction -> - ReactionInfo( - reactionString = try { - reaction.toString() - } catch (e: Exception) { - "" - }, - inboundDependencies = reaction.inboundDependencies.map { it.toString() }.sorted(), - outboundDependencies = reaction.outboundDependencies.map { it.toString() }.sorted(), - ) - }.sortedBy { it.toString() } - - val yamlReactions = yamlNodes.flatMap { it.reactions }.map { reaction -> - ReactionInfo( - reactionString = try { - reaction.toString() - } catch (e: Exception) { - "" - }, - inboundDependencies = reaction.inboundDependencies.map { it.toString() }.sorted(), - outboundDependencies = reaction.outboundDependencies.map { it.toString() }.sorted(), - ) - }.sortedBy { it.toString() } + val dslReactions = extractReactionInfo(dslNodes) + val yamlReactions = extractReactionInfo(yamlNodes) assertEquals( yamlReactions, @@ -343,7 +321,7 @@ object StaticComparisonHelper { } /** - * Data class to represent reaction information for comparison + * Data class to represent reaction information for comparison. */ private data class ReactionInfo( val reactionString: String, @@ -354,8 +332,22 @@ object StaticComparisonHelper { "Reaction(string='$reactionString', inbound=$inboundDependencies, outbound=$outboundDependencies)" } + private fun extractReactionInfo(nodes: List>): List = nodes.flatMap { + it.reactions + }.map { reaction -> + ReactionInfo( + reactionString = try { + reaction.toString() + } catch (e: Exception) { + "" + }, + inboundDependencies = reaction.inboundDependencies.map { it.toString() }.sorted(), + outboundDependencies = reaction.outboundDependencies.map { it.toString() }.sorted(), + ) + }.sortedBy { it.toString() } + /** - * Compares simulation properties + * Compares simulation properties. */ private fun compareSimulationProperties(dslSimulation: Simulation<*, *>, yamlSimulation: Simulation<*, *>) { println("Comparing simulation properties...") @@ -449,7 +441,7 @@ object StaticComparisonHelper { } /** - * Compares layers between environments + * Compares layers between environments. */ private fun > compareLayers(dslEnv: Environment, yamlEnv: Environment) { println("Comparing layers...") @@ -474,52 +466,6 @@ object StaticComparisonHelper { "Layer types should match", ) - // Compare layer values at sample positions - compareLayerValues(dslEnv, yamlEnv) - } - - /** - * Compares layer values at sample positions - */ - private fun > compareLayerValues(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing layer values...") - - // Sample positions to test layer values - val samplePositions = mutableListOf

() - - // Add positions from both environments' nodes - samplePositions.addAll(dslEnv.nodes.map { dslEnv.getPosition(it) }) - samplePositions.addAll(yamlEnv.nodes.map { yamlEnv.getPosition(it) }) - - // Remove duplicates - val uniquePositions = samplePositions.distinct() - - if (uniquePositions.isNotEmpty()) { - for (position in uniquePositions) { - val dslLayerValues = dslEnv.layers.map { (it.getValue(position)) } - val yamlLayerValues = yamlEnv.layers.map { it.getValue(position) } - // Convert all values to Double for comparison to handle Int vs Double differences - val dslDoubleValues = dslLayerValues.map { value -> - when (value) { - is Number -> value.toDouble() - else -> value.toString().toDoubleOrNull() ?: 0.0 - } - } - val yamlDoubleValues = yamlLayerValues.map { value -> - when (value) { - is Number -> value.toDouble() - else -> value.toString().toDoubleOrNull() ?: 0.0 - } - } - - assertEquals( - dslDoubleValues, - yamlDoubleValues, - "Layer values at position $position should match", - ) - } - } else { - println("Skipping layer value comparison - no valid positions found") - } + LayerComparisonUtils.compareLayerValues(dslEnv, yamlEnv) } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt index 82538f2896..d32dfabed0 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt @@ -20,12 +20,12 @@ import it.unibo.alchemist.model.Position object TestComparators { /** - * Compares a DSL loader with a YAML loader + * Compares a DSL loader with a YAML loader. * - * @param dslLoader The DSL loader to compare - * @param yamlResource The YAML resource path to compare against - * @param includeRuntime Whether to include runtime behavior comparison - * @param steps The number of steps for runtime comparison (only used if includeRuntime is true) + * @param dslLoader The DSL loader to compare. + * @param yamlResource The YAML resource path to compare against. + * @param includeRuntime Whether to include runtime behavior comparison. + * @param steps The number of steps for runtime comparison (only used if includeRuntime is true). */ fun > compare( dslLoader: () -> Loader, @@ -46,12 +46,12 @@ object TestComparators { } /** - * Compares DSL code with a YAML resource + * Compares DSL code with a YAML resource. * - * @param dslCode The DSL code resource path - * @param yamlResource The YAML resource path to compare against - * @param includeRuntime Whether to include runtime behavior comparison - * @param steps The number of steps for runtime comparison (only used if includeRuntime is true) + * @param dslCode The DSL code resource path. + * @param yamlResource The YAML resource path to compare against. + * @param includeRuntime Whether to include runtime behavior comparison. + * @param steps The number of steps for runtime comparison (only used if includeRuntime is true). */ fun > compare( dslCode: String, @@ -63,18 +63,38 @@ object TestComparators { LoaderFactory.loadDsl(dslCode) }, yamlResource, includeRuntime, steps) } + + fun > compare( + dslLoader: Loader, + yamlLoader: Loader, + includeRuntime: Boolean = false, + steps: Long = 1000L, + ) { + // Always perform static comparison + StaticComparisonHelper.compareBasicProperties(dslLoader, yamlLoader) + StaticComparisonHelper.compareSimulations(dslLoader, yamlLoader) + + // Optionally perform runtime comparison + if (includeRuntime) { + RuntimeComparisonHelper.compareLoaders(dslLoader, yamlLoader, steps) + } + } } /** - * Extension function for easier test writing with static comparison only + * Extension function for easier test writing with static comparison only. */ fun Loader.shouldEqual(yamlResource: String) { @Suppress("UNCHECKED_CAST") TestComparators.compare({ this }, yamlResource, includeRuntime = false) } +fun Loader.shouldEqual(other: Loader, includeRuntime: Boolean = true) { + @Suppress("UNCHECKED_CAST") + TestComparators.compare(this, other, includeRuntime = includeRuntime) +} /** - * Extension function for comparing DSL function with YAML resource + * Extension function for comparing DSL function with YAML resource. */ fun (() -> Loader).shouldEqual(yamlResource: String, includeRuntime: Boolean = true, steps: Long = 3000L) { @Suppress("UNCHECKED_CAST") From 08618a2ed7b37a0c518a9972972d058d905b13ce Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 8 Nov 2025 16:04:23 +0100 Subject: [PATCH 024/196] feat!: add support for alchemist.kts file loading --- .../boundary/AlchemistLoaderProvider.kt | 52 +++++++++++ .../boundary/dsl/aliases/Extractors.kt | 17 ++++ .../boundary/dsl/scripting/AlchemistScript.kt | 86 +++++++++++++++++++ .../alchemist/dsl/KotlinDslProviderTest.kt | 76 ++++++++++++++++ 4 files changed, 231 insertions(+) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/AlchemistLoaderProvider.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/aliases/Extractors.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/AlchemistLoaderProvider.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/AlchemistLoaderProvider.kt new file mode 100644 index 0000000000..a1936ac090 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/AlchemistLoaderProvider.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary + +import java.io.InputStream +import java.io.Reader +import java.net.URL + +/** + * Provider interface for loading Alchemist simulations from various input sources. + */ +interface AlchemistLoaderProvider : Extensions { + + /** + * Creates a [Loader] from a string input. + * + * @param input The input string containing the simulation configuration. + * @return A [Loader] instance. + */ + fun from(input: String): Loader + + /** + * Creates a [Loader] from a [Reader] input. + * + * @param input The reader containing the simulation configuration. + * @return A [Loader] instance. + */ + fun from(input: Reader): Loader = from(input.readText()) + + /** + * Creates a [Loader] from an [InputStream] input. + * + * @param input The input stream containing the simulation configuration. + * @return A [Loader] instance. + */ + fun from(input: InputStream): Loader = from(input.reader()) + + /** + * Creates a [Loader] from a [URL] input. + * + * @param input The URL pointing to the simulation configuration. + * @return A [Loader] instance. + */ + fun from(input: URL): Loader = from(input.openStream()) +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/aliases/Extractors.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/aliases/Extractors.kt new file mode 100644 index 0000000000..85b7a0418d --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/aliases/Extractors.kt @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.aliases + +import it.unibo.alchemist.boundary.extractors.Time + +/** + * Helper to disambiguate Time() in scripts: resolves to the extractor, not the model type. + */ +fun Time(precision: Int? = null): Time = Time(precision) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt new file mode 100644 index 0000000000..037e11e12c --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.scripting + +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import java.io.File +import kotlin.script.experimental.annotations.KotlinScript +import kotlin.script.experimental.api.ScriptCompilationConfiguration +import kotlin.script.experimental.api.compilerOptions +import kotlin.script.experimental.api.defaultImports +import kotlin.script.experimental.jvm.dependenciesFromClassContext +import kotlin.script.experimental.jvm.jvm + +/** + * Base interface for Alchemist Kotlin DSL scripts. + */ +@KotlinScript( + displayName = "Alchemist Kotlin DSL", + fileExtension = "alchemist.kts", + compilationConfiguration = AlchemistCompilationConfiguration::class, +) +interface AlchemistScript + +/** + * Compilation configuration for Alchemist scripts. + */ +object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ + defaultImports(*loadDefaultImports().toTypedArray()) + + jvm { + dependenciesFromClassContext(AlchemistScript::class, wholeClasspath = true) + compilerOptions.append("-Xcontext-parameters") + } +}) { + @Suppress("UnusedPrivateMember") + private fun readResolve(): Any = AlchemistCompilationConfiguration +} + +private fun loadDefaultImports(): List { + val defaultImports = listOf( + "it.unibo.alchemist.boundary.dsl.Dsl.simulation", + "it.unibo.alchemist.boundary.dsl.model.Incarnation.*", + "it.unibo.alchemist.boundary.dsl.generated.*", + "it.unibo.alchemist.boundary.dsl.*", + "it.unibo.alchemist.model.*", + ) + + val configFileName = "alchemist-default-imports.json" + val type = object : TypeToken>() {}.type + val mergedImports = defaultImports.toMutableList() + val seenImports = defaultImports.toMutableSet() + + fun loadAndMergeImports(json: String) { + try { + val loadedImports = Gson().fromJson>(json, type) ?: return + loadedImports.forEach { import -> + if (seenImports.add(import)) { + mergedImports.add(import) + } + } + } catch (e: Exception) { + } + } + + val externalFile = File(configFileName) + if (externalFile.exists() && externalFile.isFile) { + loadAndMergeImports(externalFile.readText()) + } else { + val resourceStream = AlchemistScript::class.java.classLoader + .getResourceAsStream(configFileName) + if (resourceStream != null) { + val json = resourceStream.bufferedReader().use { it.readText() } + loadAndMergeImports(json) + } + } + + return mergedImports +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt new file mode 100644 index 0000000000..e1711174e0 --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.boundary.LoadAlchemist +import java.io.File +import java.nio.file.Files +import kotlin.io.path.writeText +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Test + +class KotlinDslProviderTest { + @Test + fun loadSimpleScript() { + val script = """ + val inc = SAPERE.incarnation() + simulation(inc) { + networkModel = ConnectWithinDistance(5.0) + deployments { + deploy(point(0.0, 0.0)) + deploy(Point(environment, 0.0, 1.0)) + } + } + """.trimIndent() + val path = Files.createTempFile("dsl-test-", ".alchemist.kts") + path.writeText(script) + val loader = LoadAlchemist.from(path.toFile()) + assertNotNull(loader) + } + + @Test + fun loadFromFile() { + val dslUrl = requireNotNull(this.javaClass.getResource("/dsl/kts/15-variables.alchemist.kts")) { + "Resource /dsl/kts/15-variables.alchemist.kts not found on test classpath" + } + val dslFile = File(dslUrl.toURI()) + val dslLoader = { LoadAlchemist.from(dslFile) } + dslLoader.shouldEqual("dsl/yml/15-variables.yml") + } + + @Test + fun loadFromFile2() { + val dslUrl = requireNotNull(this.javaClass.getResource("/dsl/kts/14-exporters.alchemist.kts")) { + "Resource /dsl/kts/14-exporters.alchemist.kts not found on test classpath" + } + val dslFile = File(dslUrl.toURI()) + val dslLoader = { LoadAlchemist.from(dslFile) } + dslLoader.shouldEqual("dsl/yml/14-exporters.yml") + } + + @Test + fun loadFromFile3() { + val dslUrl = requireNotNull(this.javaClass.getResource("/dsl/kts/18-properties.alchemist.kts")) { + "Resource /dsl/kts/18-properties.alchemist.kts not found on test classpath" + } + val dslFile = File(dslUrl.toURI()) + val dslLoader = { LoadAlchemist.from(dslFile) } + dslLoader.shouldEqual("dsl/yml/18-properties.yml") + } + + @Test + fun testUrlLoader() { + val dslUrl = requireNotNull(this.javaClass.getResource("/dsl/kts/12-layers.alchemist.kts")) { + "Resource /dsl/kts/12-layers.alchemist.kts not found on test classpath" + } + val dslLoader = { LoadAlchemist.from(dslUrl) } + dslLoader.shouldEqual("dsl/yml/12-layers.yml") + } +} From a6bf8600062ca619f27794b927af58dc6102b3ae Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 8 Nov 2025 16:06:15 +0100 Subject: [PATCH 025/196] feat!: add support for alchemist.kts file loading --- .../boundary/AlchemistModelProvider.kt | 6 +- .../it/unibo/alchemist/boundary/Extensions.kt | 20 +++++++ .../unibo/alchemist/boundary/LoadAlchemist.kt | 30 ++++++++-- .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 46 +++++++++++++++- .../{DslLoader.kt => SingleUseDslLoader.kt} | 18 +++++- .../boundary/dsl/model/DeploymentsContext.kt | 4 +- .../boundary/dsl/model/LayerContext.kt | 15 ++++- .../boundary/dsl/model/ProgramsContext.kt | 2 +- .../boundary/dsl/model/PropertiesContext.kt | 12 ++-- .../boundary/dsl/model/SimulationContext.kt | 2 + .../boundary/dsl/model/VariablesContext.kt | 4 +- .../boundary/dsl/util/LoadingSystemLogger.kt | 18 ++++++ .../modelproviders/KotlinDslProvider.kt | 55 +++++++++++++++++++ kotlinscripting.xml | 16 ++++++ 14 files changed, 224 insertions(+), 24 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Extensions.kt rename alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/{DslLoader.kt => SingleUseDslLoader.kt} (81%) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt create mode 100644 kotlinscripting.xml diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/AlchemistModelProvider.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/AlchemistModelProvider.kt index 5a1dc02d4e..10215365a1 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/AlchemistModelProvider.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/AlchemistModelProvider.kt @@ -16,11 +16,7 @@ import java.net.URL /** * Translates inputs to a Map representing the Alchemist model. */ -interface AlchemistModelProvider { - /** - * A [Regex] matching the file extensions supported by this provider. - */ - val fileExtensions: Regex +interface AlchemistModelProvider : Extensions { /** * Reads [input] from a [String]. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Extensions.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Extensions.kt new file mode 100644 index 0000000000..32f9befeb1 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Extensions.kt @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary + +/** + * Interface for extensions that provide file extension matching. + */ +interface Extensions { + /** + * A [Regex] matching the file extensions supported. + */ + val fileExtensions: Regex +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/LoadAlchemist.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/LoadAlchemist.kt index 70ff3a74de..b2972d0119 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/LoadAlchemist.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/LoadAlchemist.kt @@ -72,16 +72,28 @@ object LoadAlchemist { */ @JvmStatic @JvmOverloads - fun from(url: URL, overrides: List = emptyList()): Loader = - from(url, modelForExtension(url.path.takeLastWhile { it != '.' }), overrides) + fun from(url: URL, overrides: List = emptyList()): Loader { + val ext = url.path.takeLastWhile { it != '.' } + return if (ext.equals("kts", ignoreCase = true)) { + loaderProviderFor(ext).from(url.openStream()) + } else { + from(url, modelForExtension(ext), overrides) + } + } /** * Load from a [file] with overrides. */ @JvmStatic @JvmOverloads - fun from(file: File, overrides: List = emptyList()): Loader = - from(file.inputStream(), modelForExtension(file.extension), overrides) + fun from(file: File, overrides: List = emptyList()): Loader { + val ext = file.extension + return if (ext.equals("kts", ignoreCase = true)) { + loaderProviderFor(ext).from(file.inputStream()) + } else { + from(file.inputStream(), modelForExtension(ext), overrides) + } + } /** * Load from a [string] with overrides. @@ -91,8 +103,14 @@ object LoadAlchemist { fun from(string: String, overrides: List = emptyList()): Loader = from(File(string), overrides) @JvmStatic - private fun modelForExtension(extension: String) = ClassPathScanner - .subTypesOf(extractPackageFrom()) + private fun modelForExtension(extension: String) = loadForExtension(extension) + + @JvmStatic + private fun loaderProviderFor(extension: String) = loadForExtension(extension) + + @JvmStatic + private inline fun loadForExtension(extension: String) = ClassPathScanner + .subTypesOf(extractPackageFrom()) .mapNotNull { it.kotlin.objectInstance } .filter { it.fileExtensions.matches(extension) } .also { require(it.size == 1) { "None or conflicting loaders for extension $extension: $it" } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index b498488f57..a74f050972 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -23,8 +23,17 @@ import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.positions.Euclidean2DPosition import kotlin.jvm.optionals.getOrElse +/** + * Main DSL object for creating Alchemist simulations. + */ object Dsl { - fun > createLoader(dsl: SimulationContext): Loader = object : DslLoader(dsl) { + /** + * Creates a loader from a simulation context. + * + * @param dsl The simulation context. + * @return A loader instance. + */ + fun > createLoader(dsl: SimulationContext): Loader = object : SingleUseDslLoader(dsl) { override val constants: Map = emptyMap() // not needed override val dependentVariables: Map> = emptyMap() // not needed override val variables: Map> = dsl.variablesContext.variables @@ -32,24 +41,55 @@ object Dsl { override val launcher: Launcher = dsl.launcher } + /** + * Converts an Incarnation enum to an Incarnation instance. + * + * @return The incarnation instance. + */ fun > Inc.incarnation(): Incarnation = SupportedIncarnations.get(this.name).getOrElse { throw IllegalArgumentException("Incarnation $this not supported") } + /** + * Creates a simulation with a custom environment. + * + * @param incarnation The incarnation instance. + * @param environment The environment instance. + * @param block The simulation configuration block. + * @return A loader instance. + */ fun > simulation( incarnation: Incarnation, environment: Environment, block: SimulationContext.() -> Unit, - ): Loader = createLoader(SimulationContext(incarnation, environment).apply(block)) + ): Loader { + val ctx = SimulationContext(incarnation, environment) + @Suppress("UNCHECKED_CAST") + context(ctx.environment as Environment<*, *>, ctx.incarnation as Incarnation<*, *>) { + ctx.apply(block) + } + return createLoader(ctx) + } + /** + * Creates a simulation with a default 2D continuous environment. + * + * @param incarnation The incarnation instance. + * @param block The simulation configuration block. + * @return A loader instance. + */ fun > simulation( incarnation: Incarnation, block: SimulationContext.() -> Unit, ): Loader { @Suppress("UNCHECKED_CAST") val defaultEnv = Continuous2DEnvironment(incarnation as Incarnation) - val ctx = SimulationContext(incarnation, defaultEnv).apply(block) + val ctx = SimulationContext(incarnation, defaultEnv) + @Suppress("UNCHECKED_CAST") + context(ctx.environment, ctx.incarnation) { + ctx.apply(block) + } return createLoader(ctx) } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt similarity index 81% rename from alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt rename to alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt index ea608a5e32..de4138a107 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DslLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt @@ -18,10 +18,26 @@ import it.unibo.alchemist.core.Engine import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position +import java.util.concurrent.Semaphore + +/** + * Abstract base class for single-use DSL loaders. + * + * @param ctx The simulation context. + */ +abstract class SingleUseDslLoader(private val ctx: SimulationContext<*, *>) : Loader { + private val mutex = Semaphore(1) + private var consumed = false -abstract class DslLoader(private val ctx: SimulationContext<*, *>) : Loader { @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation { + try { + mutex.acquireUninterruptibly() + check(!consumed) { "This loader has already been consumed! This is a bug in Alchemist" } + consumed = true + } finally { + mutex.release() + } values.forEach { (t, u) -> ctx.variablesContext.references[t] = u as Any } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index d12e76968b..c2243ff8e5 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -9,7 +9,7 @@ package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger +import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node @@ -127,7 +127,7 @@ open class DeploymentsContext>(val ctx: SimulationContext = PropertiesContext() + var propertiesContext: PropertiesContext = PropertiesContext(this@DeploymentsContext) /** * The programs context for this deployment. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt index bc97f7b05c..e45bf2aa04 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt @@ -12,7 +12,20 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.Position -class LayerContext>(ctx: SimulationContext) { +/** + * Context for configuring layers in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +class LayerContext> { + /** + * The molecule name for the layer. + */ var molecule: String? = null + + /** + * The layer instance. + */ var layer: Layer? = null } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt index 6e69c49683..fd369345d6 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt @@ -1,6 +1,6 @@ package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger +import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Condition import it.unibo.alchemist.model.Node diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt index 72e36a63b2..220ad12d30 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt @@ -1,6 +1,6 @@ package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger +import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.NodeProperty import it.unibo.alchemist.model.Position @@ -12,7 +12,7 @@ import it.unibo.alchemist.model.PositionBasedFilter * @param T The type of molecule concentration. * @param P The type of position. */ -class PropertiesContext> { +class PropertiesContext>(val ctx: DeploymentsContext) { /** * List of property contexts with their associated filters. */ @@ -50,7 +50,7 @@ class PropertiesContext> { fun applyToNode(node: Node, position: P) { propertiesCtx.forEach { (propertyCtx, filter) -> if (filter == null || filter.contains(position)) { - val properties = PropertyContext(filter, node) + val properties = PropertyContext(filter, node, this) .apply(propertyCtx) .properties properties.forEach { property -> @@ -67,7 +67,11 @@ class PropertiesContext> { * @param filter Optional position filter. * @param node The node to configure properties for. */ - inner class PropertyContext(val filter: PositionBasedFilter

?, val node: Node) { + inner class PropertyContext( + val filter: PositionBasedFilter

?, + val node: Node, + val ctx: PropertiesContext, + ) { /** * List of properties to add to the node. */ diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 9ee9c3c455..e6a03afcc6 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -14,6 +14,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.Variable +import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.boundary.launchers.DefaultLauncher import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GlobalReaction @@ -161,6 +162,7 @@ class SimulationContext>(val incarnation: Incarnation, "There must be a single layer per molecule" } val molecule = incarnation.createMolecule(moleculeName) + logger.debug("Adding layer for molecule {}: {}", moleculeName, layer) layers[moleculeName] = layer environment.addLayer(molecule, layer) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt index 75d00a3aee..a53dec3975 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt @@ -10,6 +10,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.Variable +import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import java.io.Serializable import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadWriteProperty @@ -68,7 +69,7 @@ class VariablesContext { check(!variables.containsKey(prop.name) && !dependentVariables.contains(prop.name)) { "Variable ${prop.name} already exists" } - dependentVariables.put(prop.name, source) + dependentVariables[prop.name] = source return DependentRef(source) } } @@ -104,6 +105,7 @@ class VariablesContext { check(!variables.containsKey(prop.name) && !dependentVariables.contains(prop.name)) { "Variable ${prop.name} already exists" } + logger.debug("Registering variable: {}", prop.name) variables[prop.name] = source references[prop.name] = source.default return Ref() diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt new file mode 100644 index 0000000000..e7c4c9cb76 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.util + +import it.unibo.alchemist.boundary.dsl.SingleUseDslLoader +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +internal object LoadingSystemLogger { + val logger: Logger = LoggerFactory.getLogger(SingleUseDslLoader::class.java) +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt new file mode 100644 index 0000000000..9b78013340 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.modelproviders + +import it.unibo.alchemist.boundary.AlchemistLoaderProvider +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.dsl.scripting.AlchemistScript +import java.io.InputStream +import java.io.Reader +import java.net.URL +import kotlin.script.experimental.api.ResultValue +import kotlin.script.experimental.api.ScriptDiagnostic +import kotlin.script.experimental.api.ScriptEvaluationConfiguration +import kotlin.script.experimental.api.valueOrNull +import kotlin.script.experimental.host.toScriptSource +import kotlin.script.experimental.jvm.baseClassLoader +import kotlin.script.experimental.jvm.jvm +import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost +import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate + +/** + * Provider for loading Alchemist simulations from Kotlin DSL scripts. + */ +object KotlinDslProvider : AlchemistLoaderProvider { + override val fileExtensions: Regex = "(?i)kts".toRegex() + + override fun from(input: String): Loader { + val host = BasicJvmScriptingHost() + val compilationConfiguration = createJvmCompilationConfigurationFromTemplate() + val evaluationConfiguration = ScriptEvaluationConfiguration { + jvm { + baseClassLoader(this@KotlinDslProvider::class.java.classLoader) + } + } + val result = host.eval(input.toScriptSource(), compilationConfiguration, evaluationConfiguration) + val errors = result.reports.filter { it.severity == ScriptDiagnostic.Severity.ERROR } + require(errors.isEmpty()) { errors.joinToString("\n") { it.message } } + val value = (result.valueOrNull()?.returnValue as? ResultValue.Value)?.value + return value as? Loader + ?: error("Script must return a Loader; got ${value?.let { it::class.qualifiedName } ?: "null"}") + } + + override fun from(input: Reader): Loader = from(input.readText()) + + override fun from(input: InputStream): Loader = from(input.reader()) + + override fun from(input: URL): Loader = from(input.openStream()) +} diff --git a/kotlinscripting.xml b/kotlinscripting.xml new file mode 100644 index 0000000000..5f88afaa61 --- /dev/null +++ b/kotlinscripting.xml @@ -0,0 +1,16 @@ + + + + + + + From 4f7167a212113dfe0f0d31d347870df3e4cbd828 Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 8 Nov 2025 16:11:50 +0100 Subject: [PATCH 026/196] test: test .alchemist.kts file loading --- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 73 +++++++++++-------- .../it/unibo/alchemist/dsl/LoaderFactory.kt | 10 +-- .../dsl/kts/11-monitors.alchemist.kts | 17 +++++ .../resources/dsl/kts/12-layers.alchemist.kts | 22 ++++++ .../dsl/kts/14-exporters.alchemist.kts | 21 ++++++ .../dsl/kts/15-variables.alchemist.kts | 37 ++++++++++ .../dsl/kts/18-properties.alchemist.kts | 33 +++++++++ 7 files changed, 176 insertions(+), 37 deletions(-) create mode 100644 alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts create mode 100644 alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts create mode 100644 alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts create mode 100644 alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts create mode 100644 alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 4b1dff7d01..0a101673a9 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -15,29 +15,33 @@ import another.location.SimpleMonitor import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation +import it.unibo.alchemist.boundary.dsl.generated.RectangleFilter +import it.unibo.alchemist.boundary.dsl.generated.circle +import it.unibo.alchemist.boundary.dsl.generated.grid +import it.unibo.alchemist.boundary.dsl.generated.moleculeReader +import it.unibo.alchemist.boundary.dsl.generated.point +import it.unibo.alchemist.boundary.dsl.generated.testNode +import it.unibo.alchemist.boundary.dsl.generated.testNodeProperty import it.unibo.alchemist.boundary.dsl.model.Incarnation.PROTELIS import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE import it.unibo.alchemist.boundary.exporters.CSVExporter import it.unibo.alchemist.boundary.exportfilters.CommonFilters -import it.unibo.alchemist.boundary.extractors.MoleculeReader import it.unibo.alchemist.boundary.extractors.Time -import it.unibo.alchemist.boundary.properties.TestNodeProperty import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution -import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.deployments.Circle import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.layers.StepLayer import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.maps.actions.ReproduceGPSTrace import it.unibo.alchemist.model.maps.deployments.FromGPSTrace import it.unibo.alchemist.model.maps.environments.OSMEnvironment -import it.unibo.alchemist.model.nodes.TestNode import it.unibo.alchemist.model.positionfilters.Rectangle import it.unibo.alchemist.model.positions.Euclidean2DPosition import it.unibo.alchemist.model.reactions.Event @@ -54,7 +58,7 @@ object DslLoaderFunctions { return simulation(incarnation) { networkModel = ConnectWithinDistance(5.0) deployments { - deploy(Point(environment, 0.0, 0.0)) + deploy(point(0.0, 0.0)) deploy(Point(environment, 0.0, 1.0)) } } @@ -63,8 +67,8 @@ object DslLoaderFunctions { fun > test02ManyNodes(): Loader { val incarnation = SAPERE.incarnation() return simulation(incarnation) { - simulationGenerator = MersenneTwister(10) - scenarioGenerator = MersenneTwister(20) + simulationGenerator = MersenneTwister(10L) + scenarioGenerator = MersenneTwister(20L) networkModel = ConnectWithinDistance(0.5) deployments { deploy( @@ -85,9 +89,7 @@ object DslLoaderFunctions { return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { - val grid = Grid( - environment, - generator, + val grid = grid( -5.0, -5.0, 5.0, @@ -108,13 +110,15 @@ object DslLoaderFunctions { deployments { val hello = "hello" deploy( - Grid( - environment, generator, + grid( -5.0, -5.0, 5.0, 5.0, - 0.25, 0.25, 0.1, 0.1, + 0.25, + 0.25, + 0.1, + 0.1, ), ) { all { @@ -158,13 +162,15 @@ object DslLoaderFunctions { deployments { val token = "token" deploy( - Grid( - environment, generator, + grid( -5.0, -5.0, 5.0, 5.0, - 0.25, 0.25, 0.1, 0.1, + 0.25, + 0.25, + 0.1, + 0.1, ), ) { inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { @@ -187,7 +193,7 @@ object DslLoaderFunctions { val incarnation = PROTELIS.incarnation() return simulation(incarnation) { deployments { - deploy(Point(environment, 1.5, 0.5)) { + deploy(point(1.5, 0.5)) { programs { all { timeDistribution = +JaktaTimeDistribution( @@ -281,10 +287,14 @@ object DslLoaderFunctions { } deployments { deploy( - Grid( - environment, generator, - -5.0, -5.0, 5.0, 5.0, 0.25, - 0.1, 0.1, + grid( + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.1, + 0.1, ), ) { all { @@ -315,10 +325,9 @@ object DslLoaderFunctions { ) data( Time(), - MoleculeReader( + moleculeReader( "default_module:default_program", null, - incarnation, CommonFilters.NOFILTER.filteringPolicy, emptyList(), ), @@ -409,20 +418,19 @@ object DslLoaderFunctions { ), ) { nodes { - TestNode(env as Environment) as Node + testNode() as Node } } } } } fun > test18NodeProperties(): Loader { - val incarnation = SAPERE.incarnation() - return simulation(incarnation) { + val incarnation = SAPERE.incarnation() + val environment = Continuous2DEnvironment(incarnation) + return simulation(incarnation, environment) { deployments { deploy( - Circle( - environment, - generator, + circle( 1000, 0.0, 0.0, @@ -430,13 +438,14 @@ object DslLoaderFunctions { ), ) { properties { - val filter = Rectangle(-3.0, -3.0, 2.0, 2.0) + val filter = RectangleFilter(-3.0, -3.0, 2.0, 2.0) + // same val filter2 = Rectangle(3.0, 3.0, 2.0, 2.0) inside(filter) { - add(TestNodeProperty(node, "a")) + add(testNodeProperty("a")) } inside(filter2) { - add(TestNodeProperty(node, "b")) + add(testNodeProperty("b")) } } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt index 5a45f1c255..385fc34806 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt @@ -13,22 +13,22 @@ import it.unibo.alchemist.boundary.Loader import org.kaikikm.threadresloader.ResourceLoader /** - * Factory for creating and loading DSL and YAML loaders for testing + * Factory for creating and loading DSL and YAML loaders for testing. */ object LoaderFactory { /** - * Loads a DSL loader from a resource path + * Loads a DSL loader from a resource path. */ - fun loadDsl(dslCode: String): Loader = throw Exception("Not implemented yet") + fun loadDsl(dslCode: String): Loader = throw NotImplementedError("Not implemented yet $dslCode") /** - * Loads a YAML loader from a resource path + * Loads a YAML loader from a resource path. */ fun loadYaml(yamlResource: String): Loader = LoadAlchemist.from(ResourceLoader.getResource(yamlResource)!!) /** - * Loads both DSL and YAML loaders for comparison + * Loads both DSL and YAML loaders for comparison. */ fun loadBoth(dslCode: String, yamlResource: String): Pair = Pair(loadDsl(dslCode), loadYaml(yamlResource)) diff --git a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts new file mode 100644 index 0000000000..eae1ee6177 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts @@ -0,0 +1,17 @@ +import another.location.SimpleMonitor +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation + +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +val incarnation = SAPERE.incarnation() +simulation(incarnation) { + addMonitor(SimpleMonitor()) +} diff --git a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts new file mode 100644 index 0000000000..7643de365a --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts @@ -0,0 +1,22 @@ +val incarnation = SAPERE.incarnation() +simulation(incarnation) { + layer { + molecule = "A" + layer = StepLayer(2.0, 2.0, 100.0, 0.0) + } + layer { + molecule = "B" + layer = StepLayer(-2.0, -2.0, 0.0, 100.0) + } + deployments { + deploy( + grid(-5.0, -5.0, 5.0, 5.0, 0.25, + 0.1, 0.1, + ), + ) { + all { + molecule = "a" + } + } + } +} diff --git a/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts new file mode 100644 index 0000000000..82ebaf280d --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts @@ -0,0 +1,21 @@ +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation + +val incarnation = PROTELIS.incarnation() +simulation(incarnation) { + exporter { + type = CSVExporter( + "test_export_interval", + 4.0, + ) + data( + Time(), + moleculeReader( + "default_module:default_program", + null, + CommonFilters.NOFILTER.filteringPolicy, + emptyList(), + ), + ) + } +} diff --git a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts new file mode 100644 index 0000000000..64948c4169 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts @@ -0,0 +1,37 @@ +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation + +val incarnation = SAPERE.incarnation() +simulation(incarnation) { + val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) + val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + + val mSize by variable { -size } + val sourceStart by variable { mSize / 10.0 } + val sourceSize by variable { size / 5.0 } + + networkModel = ConnectWithinDistance(0.5) + deployments { + deploy( + grid( + mSize, mSize, size, size, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + inside(RectangleFilter(sourceStart, sourceStart, sourceSize, sourceSize)) { + molecule = "token, 0, []" + } + programs { + all { + timeDistribution(rate.toString()) + program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" + } + all { + program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" + } + } + } + } +} + + diff --git a/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts new file mode 100644 index 0000000000..eba436e196 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts @@ -0,0 +1,33 @@ +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation + +val incarnation = SAPERE.incarnation() +simulation(incarnation) { + deployments { + deploy( + circle( + 1000, + 0.0, + 0.0, + 15.0, + ), + ) { + properties { + val filter = RectangleFilter(-3.0, -3.0, 2.0, 2.0) + val filter2 = RectangleFilter(3.0, 3.0, 2.0, 2.0) + inside(filter) { + add(testNodeProperty("a")) + } + // otherwise + inside(filter2) { + add(TestNodeProperty(node, + env, + incarnation, + generator, + "b")) + } + } + } + } +} + From 27a5c1372c60d03d7cb8cd05e4659159eb58becc Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 8 Nov 2025 16:16:39 +0100 Subject: [PATCH 027/196] refactor: add external imports config file --- .../resources/alchemist-default-imports.json | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 alchemist-loading/src/main/resources/alchemist-default-imports.json diff --git a/alchemist-loading/src/main/resources/alchemist-default-imports.json b/alchemist-loading/src/main/resources/alchemist-default-imports.json new file mode 100644 index 0000000000..47756c0812 --- /dev/null +++ b/alchemist-loading/src/main/resources/alchemist-default-imports.json @@ -0,0 +1,41 @@ +[ + "it.unibo.alchemist.boundary.dsl.prelude.*", + "it.unibo.alchemist.boundary.dsl.Dsl.simulation", + "it.unibo.alchemist.boundary.dsl.Dsl.incarnation", + "it.unibo.alchemist.boundary.dsl.model.Incarnation.*", + "it.unibo.alchemist.boundary.dsl.generated.*", + "it.unibo.alchemist.model.maps.actions.*", + "it.unibo.alchemist.model.maps.deployments.*", + "it.unibo.alchemist.model.maps.environments.*", + "it.unibo.alchemist.model.*", + "it.unibo.alchemist.model.positions.*", + "it.unibo.alchemist.model.deployments.*", + "it.unibo.alchemist.model.positionfilters.And", + "it.unibo.alchemist.model.positionfilters.Or", + "it.unibo.alchemist.model.positionfilters.Not", + "it.unibo.alchemist.model.positionfilters.Xor", + "it.unibo.alchemist.model.actions.*", + "it.unibo.alchemist.model.conditions.*", + "it.unibo.alchemist.model.environments.*", + "it.unibo.alchemist.model.geometry.*", + "it.unibo.alchemist.model.layers.*", + "it.unibo.alchemist.model.linkingrules.*", + "it.unibo.alchemist.model.movestrategies.*", + "it.unibo.alchemist.model.neighborhoods.*", + "it.unibo.alchemist.model.nodes.*", + "it.unibo.alchemist.model.properties.*", + "it.unibo.alchemist.model.routes.*", + "it.unibo.alchemist.model.reactions.*", + "it.unibo.alchemist.model.terminators.*", + "it.unibo.alchemist.model.timedistributions.*", + "it.unibo.alchemist.boundary.properties.*", + "it.unibo.alchemist.boundary.dsl.aliases.*", + "it.unibo.alchemist.boundary.exporters.*", + "it.unibo.alchemist.boundary.extractors.*", + "it.unibo.alchemist.boundary.launchers.*", + "it.unibo.alchemist.boundary.statistic.*", + "it.unibo.alchemist.boundary.exportfilters.*", + "it.unibo.alchemist.boundary.variables.*", + "it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger" +] + From 78bfff8cc5e1b4e05c8b7041bac808e0a0c34afd Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 8 Nov 2025 16:36:13 +0100 Subject: [PATCH 028/196] feat!: add ksp function helpers generator add @BuildDsl annotation to automatically generate helper functions --- .../unibo/alchemist/boundary/dsl/BuildDsl.kt | 32 ++ alchemist-dsl-processor/build.gradle.kts | 13 + .../boundary/dsl/processor/BoundProcessor.kt | 88 +++ .../dsl/processor/ConstructorFinder.kt | 41 ++ .../dsl/processor/ConstructorParamBuilder.kt | 341 ++++++++++++ .../boundary/dsl/processor/ContextAccessor.kt | 68 +++ .../dsl/processor/DefaultValueAnalyzer.kt | 378 +++++++++++++ .../dsl/processor/DslBuilderProcessor.kt | 516 ++++++++++++++++++ .../processor/DslBuilderProcessorProvider.kt | 15 + .../dsl/processor/FunctionGenerator.kt | 251 +++++++++ .../boundary/dsl/processor/ImportManager.kt | 36 ++ .../dsl/processor/ParameterInjector.kt | 265 +++++++++ .../boundary/dsl/processor/ProcessorConfig.kt | 92 ++++ .../dsl/processor/TypeArgumentProcessor.kt | 199 +++++++ .../boundary/dsl/processor/TypeExtractor.kt | 129 +++++ .../dsl/processor/TypeHierarchyChecker.kt | 134 +++++ .../dsl/processor/TypeParameterHandler.kt | 208 +++++++ .../dsl/processor/ContextAccessorTest.kt | 68 +++ .../dsl/processor/ParameterInjectorTest.kt | 96 ++++ .../dsl/processor/ProcessorConfigTest.kt | 26 + .../dsl/processor/TypeParameterHandlerTest.kt | 71 +++ alchemist-loading/build.gradle.kts | 24 + .../boundary/properties/TestNodeProperty.kt | 22 +- alchemist-test/build.gradle.kts | 3 + .../kotlin/kotlin-jvm-convention.gradle.kts | 1 + ...kotlin-multiplatform-convention.gradle.kts | 1 + ...tlin-static-analysis-convention.gradle.kts | 7 + gradle/libs.versions.toml | 4 + settings.gradle.kts | 1 + 29 files changed, 3128 insertions(+), 2 deletions(-) create mode 100644 alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt create mode 100644 alchemist-dsl-processor/build.gradle.kts create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt create mode 100644 alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt create mode 100644 alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt create mode 100644 alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt create mode 100644 alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt diff --git a/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt b/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt new file mode 100644 index 0000000000..699fa9c551 --- /dev/null +++ b/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl + +/** + * Annotation used to mark classes that should have DSL builder functions generated. + * When applied to a class, the DSL processor will generate a builder function + * that can be used in Alchemist DSL scripts to create instances of the annotated class. + * + * @param functionName Custom name for the generated DSL function. If empty, defaults to + * the lowercase version of the class name with the first character lowercased. + * @param injectEnvironment Whether to inject an Environment parameter into the generated builder function. + * @param injectGenerator Whether to inject a Generator parameter into the generated builder function. + * @param injectNode Whether to inject a Node parameter into the generated builder function. + * @param injectReaction Whether to inject a Reaction parameter into the generated builder function. + */ +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.SOURCE) +annotation class BuildDsl( + val functionName: String = "", + val injectEnvironment: Boolean = true, + val injectGenerator: Boolean = true, + val injectNode: Boolean = true, + val injectReaction: Boolean = true, +) diff --git a/alchemist-dsl-processor/build.gradle.kts b/alchemist-dsl-processor/build.gradle.kts new file mode 100644 index 0000000000..6c53b57202 --- /dev/null +++ b/alchemist-dsl-processor/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("kotlin-jvm-convention") + kotlin("jvm") +} + +dependencies { + implementation(libs.ksp.api) + api(project(":alchemist-api")) +// api(project(":alchemist-dsl-api")) + + testImplementation(libs.bundles.testing.compile) + testRuntimeOnly(libs.bundles.testing.runtimeOnly) +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt new file mode 100644 index 0000000000..9b5f5922d7 --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt @@ -0,0 +1,88 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.symbol.KSTypeReference + +/** + * Processes type bounds for type parameters, cleaning up internal Kotlin type representations. + */ +object BoundProcessor { + /** + * Processes a type bound reference, cleaning up internal Kotlin type representations and variance annotations. + * + * @param bound The type reference to process + * @param classTypeParamNames List of class type parameter names to replace in the bound + * @return A cleaned string representation of the bound with fully qualified names + */ + fun processBound(bound: KSTypeReference, classTypeParamNames: List = emptyList()): String { + val resolved = bound.resolve() + val decl = resolved.declaration + val qualifiedName = decl.qualifiedName?.asString() + + if (qualifiedName != null) { + val arguments = resolved.arguments + val typeString = if (arguments.isNotEmpty()) { + val typeArgs = arguments.joinToString(", ") { arg -> + formatTypeArgument(arg, classTypeParamNames) + } + "$qualifiedName<$typeArgs>" + } else { + qualifiedName + } + + val nullableSuffix = if (resolved.isMarkedNullable) "?" else "" + val result = "$typeString$nullableSuffix" + return replaceClassTypeParamReferences(result, classTypeParamNames) + } + + val result = TypeExtractor.extractTypeString(bound, emptyList()) + return replaceClassTypeParamReferences(result, classTypeParamNames) + } + + private fun formatTypeArgument( + arg: com.google.devtools.ksp.symbol.KSTypeArgument, + classTypeParamNames: List, + ): String = when { + arg.type == null -> "*" + arg.variance == com.google.devtools.ksp.symbol.Variance.STAR -> "*" + arg.variance == com.google.devtools.ksp.symbol.Variance.CONTRAVARIANT -> { + arg.type?.let { + val typeStr = TypeExtractor.extractTypeString(it, emptyList()) + val replaced = replaceClassTypeParamReferences(typeStr, classTypeParamNames) + "in $replaced" + } ?: "*" + } + arg.variance == com.google.devtools.ksp.symbol.Variance.COVARIANT -> { + arg.type?.let { + val typeStr = TypeExtractor.extractTypeString(it, emptyList()) + val replaced = replaceClassTypeParamReferences(typeStr, classTypeParamNames) + "out $replaced" + } ?: "*" + } + else -> { + arg.type?.let { + val typeStr = TypeExtractor.extractTypeString(it, emptyList()) + replaceClassTypeParamReferences(typeStr, classTypeParamNames) + } ?: "*" + } + } + + private fun replaceClassTypeParamReferences(boundStr: String, classTypeParamNames: List): String { + if (classTypeParamNames.isEmpty()) { + return boundStr + } + var result = boundStr + classTypeParamNames.forEach { paramName -> + val pattern = Regex("""\b[\w.]+\.$paramName\b""") + result = pattern.replace(result) { matchResult -> + val matched = matchResult.value + val prefix = matched.substringBefore(".$paramName") + if (prefix.contains(".")) { + paramName + } else { + matched + } + } + } + return result + } +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt new file mode 100644 index 0000000000..36c99f19f4 --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt @@ -0,0 +1,41 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import com.google.devtools.ksp.symbol.Modifier + +/** + * Finds a suitable constructor for a class declaration. + */ +object ConstructorFinder { + /** + * Finds a public constructor for the given class declaration. + * Prefers the primary constructor, otherwise returns the constructor with the most parameters. + * + * @param classDecl The class declaration to find a constructor for + * @return The found constructor, or null if no suitable constructor exists + */ + fun findConstructor(classDecl: KSClassDeclaration): KSFunctionDeclaration? { + val primaryConstructor = classDecl.primaryConstructor + if (primaryConstructor != null && isPublicConstructor(primaryConstructor)) { + return primaryConstructor + } + + val constructors = classDecl.getAllFunctions() + .filter { function -> + val simpleName = function.simpleName.asString() + (simpleName == "" || simpleName == classDecl.simpleName.asString()) && + isPublicConstructor(function) + } + .sortedByDescending { it.parameters.size } + + return constructors.firstOrNull() + } + + private fun isPublicConstructor(function: KSFunctionDeclaration): Boolean { + val modifiers = function.modifiers + return !modifiers.contains(Modifier.PRIVATE) && + !modifiers.contains(Modifier.PROTECTED) && + !modifiers.contains(Modifier.INTERNAL) + } +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt new file mode 100644 index 0000000000..79d309d9ef --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -0,0 +1,341 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.symbol.KSValueParameter + +/** + * Builds constructor parameter expressions for DSL builder functions. + */ +object ConstructorParamBuilder { + /** + * Builds the list of constructor parameter expressions. + * + * @param allParameters All constructor parameters + * @param remainingParams Parameters that are not injected + * @param paramsToSkip Set of parameter indices to skip + * @param paramNames Names of remaining parameters + * @param injectionIndices Map of injection types to parameter indices + * @param injectedParamNames Map of injection types to parameter names + * @param annotationValues Annotation values from BuildDsl + * @param typeParamNames Type parameter names + * @param contextType The type of context + * @param hasContextParams Whether context parameters are present + * @param contextParamName Name of the context parameter + * @param injectedParamTypes Map of injection types to parameter types + * @return List of constructor parameter expressions + */ + fun buildConstructorParams( + allParameters: List, + remainingParams: List, + paramsToSkip: Set, + paramNames: List, + injectionIndices: Map, + injectedParamNames: Map, + annotationValues: Map, + typeParamNames: List, + contextType: ContextType, + hasContextParams: Boolean = false, + contextParamName: String = "ctx", + injectedParamTypes: Map = emptyMap(), + ): List = buildConstructorParamsInternal( + allParameters, + remainingParams, + paramsToSkip, + paramNames, + injectionIndices, + injectedParamNames, + annotationValues, + typeParamNames, + injectedParamTypes, + hasContextParams, + contextType, + contextParamName, + ) + + private fun isInjectionIndex( + injectionType: InjectionType, + index: Int, + injectionIndices: Map, + annotationValues: Map, + annotationKey: String, + ): Boolean = injectionIndices.containsKey(injectionType) && + index == injectionIndices[injectionType] && + (annotationValues[annotationKey] as? Boolean ?: true) + + private fun buildInjectedParam( + injectionType: InjectionType, + param: KSValueParameter, + hasContextParams: Boolean, + contextType: ContextType, + contextParamName: String, + injectedParamNames: Map, + injectedParamTypes: Map, + typeParamNames: List, + ): String { + val accessor = buildAccessor(injectionType, hasContextParams, contextType, contextParamName, injectedParamNames) + val contextParamType = injectedParamTypes[injectionType] + return if (contextParamType != null && needsCast(param.type, contextParamType, typeParamNames)) { + val castType = TypeExtractor.extractTypeString(param.type, typeParamNames) + "$accessor as $castType" + } else { + accessor + } + } + + private fun buildAccessor( + injectionType: InjectionType, + hasContextParams: Boolean, + contextType: ContextType, + contextParamName: String, + injectedParamNames: Map, + ): String { + if (!hasContextParams) { + return injectedParamNames[injectionType] ?: getDefaultParamName(injectionType) + } + + return ContextAccessor.getAccessor(injectionType, contextType, contextParamName) + } + + private fun getDefaultParamName(injectionType: InjectionType): String = when (injectionType) { + InjectionType.ENVIRONMENT -> "env" + InjectionType.GENERATOR -> "generator" + InjectionType.INCARNATION -> "incarnation" + InjectionType.NODE -> "node" + InjectionType.REACTION -> "reaction" + InjectionType.TIMEDISTRIBUTION -> "timeDistribution" + } + + private fun needsCast( + constructorParamType: com.google.devtools.ksp.symbol.KSTypeReference, + contextParamType: String, + typeParamNames: List, + ): Boolean { + val constructorTypeStr = TypeExtractor.extractTypeString(constructorParamType, typeParamNames) + + if (constructorTypeStr == contextParamType) { + return false + } + + val constructorResolved = constructorParamType.resolve() + val constructorDecl = constructorResolved.declaration + val constructorQualified = constructorDecl.qualifiedName?.asString().orEmpty() + + return when { + !contextParamType.startsWith(constructorQualified) -> true + constructorResolved.arguments.isEmpty() -> false + else -> checkWildcardCastNeeded(constructorTypeStr, contextParamType, typeParamNames) + } + } + + private fun checkWildcardCastNeeded( + constructorTypeStr: String, + contextParamType: String, + typeParamNames: List, + ): Boolean { + val constructorHasWildcards = constructorTypeStr.contains("<") && + (constructorTypeStr.contains("<*") || constructorTypeStr.contains(", *")) + + if (constructorHasWildcards) { + val contextTypeArgs = if (contextParamType.contains("<")) { + contextParamType.substringAfter("<").substringBefore(">") + } else { + "" + } + return typeParamNames.any { it in contextTypeArgs } + } + + return constructorTypeStr != contextParamType + } + + fun buildConstructorParamsForPropertyContext( + allParameters: List, + remainingParams: List, + paramsToSkip: Set, + paramNames: List, + injectionIndices: Map, + injectedParamNames: Map, + annotationValues: Map, + typeParamNames: List, + injectedParamTypes: Map = emptyMap(), + ): List = buildConstructorParamsInternal( + allParameters, + remainingParams, + paramsToSkip, + paramNames, + injectionIndices, + injectedParamNames, + annotationValues, + typeParamNames, + injectedParamTypes, + hasContextParams = true, + contextType = ContextType.PROPERTY, + contextParamName = "ctx", + ) + + fun convertToPropertyContextAccessors( + injectionIndices: Map, + allParameters: List, + remainingParams: List, + paramsToSkip: Set, + paramNames: List, + injectedParamNames: Map, + annotationValues: Map, + typeParamNames: List, + injectedParamTypes: Map, + ): List = buildConstructorParamsInternal( + allParameters, + remainingParams, + paramsToSkip, + paramNames, + injectionIndices, + injectedParamNames, + annotationValues, + typeParamNames, + injectedParamTypes, + hasContextParams = true, + contextType = ContextType.PROPERTY, + contextParamName = "ctx", + ) + + private fun buildConstructorParamsInternal( + allParameters: List, + remainingParams: List, + paramsToSkip: Set, + paramNames: List, + injectionIndices: Map, + injectedParamNames: Map, + annotationValues: Map, + typeParamNames: List, + injectedParamTypes: Map, + hasContextParams: Boolean, + contextType: ContextType, + contextParamName: String, + ): List { + val constructorParams = mutableListOf() + var remainingIndex = 0 + + allParameters.forEachIndexed { index, param -> + when { + isInjectionIndex( + InjectionType.ENVIRONMENT, + index, + injectionIndices, + annotationValues, + "injectEnvironment", + ) -> { + constructorParams.add( + buildInjectedParam( + InjectionType.ENVIRONMENT, + param, + hasContextParams, + contextType, + contextParamName, + injectedParamNames, + injectedParamTypes, + typeParamNames, + ), + ) + } + isInjectionIndex( + InjectionType.GENERATOR, + index, + injectionIndices, + annotationValues, + "injectGenerator", + ) -> { + constructorParams.add( + buildInjectedParam( + InjectionType.GENERATOR, + param, + hasContextParams, + contextType, + contextParamName, + injectedParamNames, + injectedParamTypes, + typeParamNames, + ), + ) + } + isInjectionIndex( + InjectionType.INCARNATION, + index, + injectionIndices, + annotationValues, + "injectIncarnation", + ) -> { + constructorParams.add( + buildInjectedParam( + InjectionType.INCARNATION, + param, + hasContextParams, + contextType, + contextParamName, + injectedParamNames, + injectedParamTypes, + typeParamNames, + ), + ) + } + isInjectionIndex(InjectionType.NODE, index, injectionIndices, annotationValues, "injectNode") -> { + constructorParams.add( + buildInjectedParam( + InjectionType.NODE, + param, + hasContextParams, + contextType, + contextParamName, + injectedParamNames, + injectedParamTypes, + typeParamNames, + ), + ) + } + isInjectionIndex( + InjectionType.REACTION, + index, + injectionIndices, + annotationValues, + "injectReaction", + ) -> { + constructorParams.add( + buildInjectedParam( + InjectionType.REACTION, + param, + hasContextParams, + contextType, + contextParamName, + injectedParamNames, + injectedParamTypes, + typeParamNames, + ), + ) + } + injectionIndices.containsKey(InjectionType.TIMEDISTRIBUTION) && + index == injectionIndices[InjectionType.TIMEDISTRIBUTION] -> { + constructorParams.add( + buildInjectedParam( + InjectionType.TIMEDISTRIBUTION, + param, + hasContextParams, + contextType, + contextParamName, + injectedParamNames, + injectedParamTypes, + typeParamNames, + ), + ) + } + !paramsToSkip.contains(index) -> { + val paramName = paramNames[remainingIndex] + val remainingParam = remainingParams[remainingIndex] + val paramValue = if (remainingParam.isVararg) "*$paramName" else paramName + constructorParams.add(paramValue) + remainingIndex++ + } + else -> { + constructorParams.add("null") + } + } + } + return constructorParams + } +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt new file mode 100644 index 0000000000..11d6c8718a --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt @@ -0,0 +1,68 @@ +package it.unibo.alchemist.boundary.dsl.processor + +/** + * Provides accessor paths for injected parameters based on context type. + */ +object ContextAccessor { + /** + * Gets the accessor path for an injected parameter based on the context type. + * + * @param injectionType The type of injection (ENVIRONMENT, GENERATOR, INCARNATION, NODE, REACTION, TIMEDISTRIBUTION) + * @param contextType The context type (SIMULATION, DEPLOYMENT, PROGRAM, PROPERTY) + * @param contextParamName The name of the context parameter (default: "ctx") + * @return The accessor path string + */ + fun getAccessor(injectionType: InjectionType, contextType: ContextType, contextParamName: String = "ctx"): String = + when (contextType) { + ContextType.SIMULATION -> getSimulationAccessor(injectionType, contextParamName) + ContextType.DEPLOYMENT -> getDeploymentAccessor(injectionType, contextParamName) + ContextType.PROGRAM -> getProgramAccessor(injectionType, contextParamName) + ContextType.PROPERTY -> getPropertyAccessor(injectionType, contextParamName) + } + + private fun getSimulationAccessor(injectionType: InjectionType, contextParamName: String): String = + when (injectionType) { + InjectionType.ENVIRONMENT -> "$contextParamName.environment" + InjectionType.GENERATOR -> "$contextParamName.scenarioGenerator" + InjectionType.INCARNATION -> "$contextParamName.incarnation" + InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in SimulationContext") + InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in SimulationContext") + InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( + "TIMEDISTRIBUTION is not available in SimulationContext", + ) + } + + private fun getDeploymentAccessor(injectionType: InjectionType, contextParamName: String): String = + when (injectionType) { + InjectionType.ENVIRONMENT -> "$contextParamName.env" + InjectionType.GENERATOR -> "$contextParamName.generator" + InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" + InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in DeploymentsContext") + InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in DeploymentsContext") + InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( + "TIMEDISTRIBUTION is not available in DeploymentsContext", + ) + } + + private fun getProgramAccessor(injectionType: InjectionType, contextParamName: String): String = + when (injectionType) { + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.env" + InjectionType.GENERATOR -> "$contextParamName.ctx.ctx.generator" + InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.ctx.incarnation" + InjectionType.NODE -> "$contextParamName.node" + InjectionType.REACTION -> "$contextParamName.reaction" + InjectionType.TIMEDISTRIBUTION -> "$contextParamName.timeDistribution!!" + } + + private fun getPropertyAccessor(injectionType: InjectionType, contextParamName: String): String = + when (injectionType) { + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.env" + InjectionType.GENERATOR -> "$contextParamName.ctx.ctx.generator" + InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.ctx.incarnation" + InjectionType.NODE -> "$contextParamName.node" + InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in PropertyContext") + InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( + "TIMEDISTRIBUTION is not available in PropertyContext", + ) + } +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt new file mode 100644 index 0000000000..30dce50d9b --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt @@ -0,0 +1,378 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.containingFile +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSValueParameter +import java.io.File +import java.io.IOException + +/** + * Analyzes and extracts default values from constructor parameters. + */ +object DefaultValueAnalyzer { + private val MATH_CONSTANTS = setOf("PI", "E") + private val MATH_FUNCTIONS = setOf( + "sin", "cos", "tan", "asin", "acos", "atan", "atan2", + "sinh", "cosh", "tanh", "exp", "log", "log10", "sqrt", "abs", "ceil", "floor", + "round", "max", "min", "pow", + ) + private val BUILTIN_TYPES = setOf("Double", "Int", "Long", "Float", "String", "Boolean", "List", "Map", "Set") + + /** + * Extracts default values for all parameters that have them. + * + * @param remainingParams The parameters to extract default values from + * @param classDecl The class declaration (unused, kept for API compatibility) + * @return List of default value strings, null for parameters without defaults + */ + @Suppress("UNUSED_PARAMETER") + fun extractAllDefaultValues(remainingParams: List, classDecl: KSClassDeclaration): List = + remainingParams.mapNotNull { param -> + if (param.hasDefault) { + tryExtractDefaultFromSource(param) + } else { + null + } + } + + /** + * Extracts import statements needed for default value expressions. + * + * @param defaultValues List of default value strings + * @param classDecl The class declaration to analyze imports from + * @return Set of import statements needed + */ + fun extractNeededImportsFromDefaults(defaultValues: List, classDecl: KSClassDeclaration): Set { + val neededImports = mutableSetOf() + val defaultValueText = defaultValues.joinToString(" ") + val sourceImports = getSourceFileImports(classDecl) + + neededImports.addAll(extractIdentifierImports(defaultValueText, sourceImports)) + + return neededImports + } + + private fun extractIdentifierImports(defaultValueText: String, sourceImports: List): Set { + val neededImports = mutableSetOf() + + val identifierPattern = Regex("""\b([A-Z][a-zA-Z0-9]*)\b""") + val matches = identifierPattern.findAll(defaultValueText) + for (match in matches) { + val identifier = match.groupValues[1] + if (identifier !in MATH_CONSTANTS && identifier !in MATH_FUNCTIONS && identifier !in BUILTIN_TYPES) { + val qualifiedPattern = Regex("""\w+\.$identifier\b""") + if (!qualifiedPattern.containsMatchIn(defaultValueText)) { + addImportIfNeeded(identifier, defaultValueText, sourceImports, null, neededImports) + } + } + } + + return neededImports + } + + private fun addImportIfNeeded( + identifier: String, + defaultValueText: String, + sourceImports: List, + defaultPackage: String?, + neededImports: MutableSet, + ) { + val pattern = Regex("""\b$identifier\b""") + if (pattern.containsMatchIn(defaultValueText)) { + val qualifiedPattern = Regex("""\w+\.$identifier""") + if (!qualifiedPattern.containsMatchIn(defaultValueText)) { + val import = findImportForIdentifier(identifier, sourceImports, defaultPackage) + if (import != null) { + neededImports.add(import) + } + } + } + } + + private fun getSourceFileImports(classDecl: KSClassDeclaration): List = try { + val file = classDecl.containingFile + if (file != null) { + val filePath = file.filePath + run { + val sourceCode = File(filePath).readText() + val importPattern = Regex("""^import\s+(.+)$""", RegexOption.MULTILINE) + importPattern.findAll(sourceCode).map { it.groupValues[1] }.toList() + } + } else { + emptyList() + } + } catch (e: IOException) { + throw IllegalStateException("Failed to read source file imports", e) + } + + private fun findImportForIdentifier( + identifier: String, + sourceImports: List, + defaultPackage: String?, + ): String? { + val explicitImport = sourceImports.find { it.endsWith(".$identifier") } + if (explicitImport != null) { + return "import $explicitImport" + } + + return if (defaultPackage != null) { + "import $defaultPackage.$identifier" + } else { + null + } + } + + /** + * Attempts to extract a default value from the source code for a parameter. + * + * @param param The parameter to extract the default value for + * @return The default value string, or null if not found or extraction fails + */ + @Suppress("SwallowedException") + fun tryExtractDefaultFromSource(param: KSValueParameter): String? = try { + extractDefaultValueFromFile(param) + } catch (e: IOException) { + null + } + + private fun extractDefaultValueFromFile(param: KSValueParameter): String? { + val extractionData = prepareExtractionData(param) ?: return null + val defaultValue = extractBalancedExpression(extractionData.sourceCode, extractionData.startIndex) + val trimmed = defaultValue?.trim()?.takeIf { it.isNotEmpty() && !it.contains("\n") } + val result = if (trimmed == null && param.hasDefault) { + val paramName = param.name?.asString() ?: return null + tryExtractSimpleDefault(extractionData.sourceCode, paramName) + } else { + trimmed + } + return result?.let { qualifyMathIdentifiers(it) } + } + + private fun qualifyMathIdentifiers(defaultValue: String): String { + val replacements = mutableListOf>() + + for (constant in MATH_CONSTANTS) { + val pattern = Regex("""\b$constant\b""") + val qualifiedPattern = Regex("""\w+\.$constant\b""") + if (pattern.containsMatchIn(defaultValue) && !qualifiedPattern.containsMatchIn(defaultValue)) { + pattern.findAll(defaultValue).forEach { match -> + val before = defaultValue.substring(0, match.range.first) + val isQualified = before.endsWith(".") || before.endsWith("::") + if (!isQualified) { + replacements.add(match.range to "kotlin.math.${match.value}") + } + } + } + } + + for (function in MATH_FUNCTIONS) { + val pattern = Regex("""\b$function\s*\(""") + val qualifiedPattern = Regex("""\w+\.$function\s*\(""") + if (pattern.containsMatchIn(defaultValue) && !qualifiedPattern.containsMatchIn(defaultValue)) { + pattern.findAll(defaultValue).forEach { match -> + val before = defaultValue.substring(0, match.range.first) + val isQualified = before.endsWith(".") || before.endsWith("::") + if (!isQualified) { + replacements.add(match.range to "kotlin.math.${match.value}") + } + } + } + } + + if (replacements.isEmpty()) { + return defaultValue + } + + replacements.sortByDescending { it.first.first } + + var result = defaultValue + for ((range, replacement) in replacements) { + result = result.replaceRange(range, replacement) + } + + return result + } + + private fun tryExtractSimpleDefault(sourceCode: String, paramName: String): String? { + val escapedName = Regex.escape(paramName) + val modifierPattern = """(?:private\s+|public\s+|protected\s+|internal\s+)?""" + val valVarPattern = """(?:val\s+|var\s+)?""" + val typePattern = """[^=,)]+""" + val valuePattern = """([^,\n)]+)""" + val patternWithModifiers = Regex( + """$modifierPattern$valVarPattern$escapedName\s*:\s*$typePattern=\s*$valuePattern""", + RegexOption.MULTILINE, + ) + val patternSimple = Regex( + """$escapedName\s*:\s*$typePattern=\s*$valuePattern""", + RegexOption.MULTILINE, + ) + val patterns = listOf(patternWithModifiers, patternSimple) + for (pattern in patterns) { + val match = pattern.find(sourceCode) + if (match != null && match.groupValues.size > 1) { + val value = match.groupValues[1].trim().trimEnd(',', ')') + if (value.isNotEmpty()) { + return value + } + } + } + return null + } + + private data class ExtractionData(val sourceCode: String, val startIndex: Int) + + private fun prepareExtractionData(param: KSValueParameter): ExtractionData? { + val validationResult = validateExtractionPrerequisites(param) ?: return null + val startIndex = findParameterDefaultStart(validationResult.sourceCode, validationResult.paramName) + return if (startIndex != null) { + ExtractionData(validationResult.sourceCode, startIndex) + } else { + null + } + } + + private data class ValidationResult(val sourceCode: String, val paramName: String) + + private fun validateExtractionPrerequisites(param: KSValueParameter): ValidationResult? { + val file = param.containingFile + val paramName = param.name?.asString() + return if (file != null && paramName != null) { + readSourceFile(file.filePath)?.let { ValidationResult(it, paramName) } + } else { + null + } + } + + @Suppress("SwallowedException") + private fun readSourceFile(filePath: String): String? = try { + File(filePath).readText() + } catch (e: IOException) { + null + } + + private fun findParameterDefaultStart(sourceCode: String, paramName: String): Int? { + val escapedName = Regex.escape(paramName) + val pattern = Regex( + """(?:private\s+|public\s+|protected\s+|internal\s+)?(?:val\s+|var\s+)?$escapedName\s*:\s*[^=,)]+=\s*""", + RegexOption.MULTILINE, + ) + val match = pattern.find(sourceCode) ?: return null + return match.range.last + 1 + } + + private fun extractBalancedExpression(sourceCode: String, startIndex: Int): String? { + if (startIndex >= sourceCode.length) return null + + val state = ExtractionState(startIndex) + val result = StringBuilder() + + while (state.index < sourceCode.length) { + val char = sourceCode[state.index] + val shouldContinue = processCharacter(char, sourceCode, state, result) + if (!shouldContinue) { + break + } + state.index++ + } + + return result.toString().trim().takeIf { it.isNotEmpty() } + } + + private data class ExtractionState( + var index: Int, + var depth: Int = 0, + var inString: Boolean = false, + var stringChar: Char? = null, + val bracketStack: MutableList = mutableListOf(), + ) + + private fun processCharacter( + char: Char, + sourceCode: String, + state: ExtractionState, + result: StringBuilder, + ): Boolean = when { + handleStringStart(char, state, result) -> true + handleStringEnd(char, sourceCode, state, result) -> true + state.inString -> { + result.append(char) + true + } + handleOpeningBracket(char, state, result) -> true + handleClosingBracket(char, state, result) -> false + handleParameterSeparator(char, state) -> false + else -> { + result.append(char) + true + } + } + + private fun handleStringStart(char: Char, state: ExtractionState, result: StringBuilder): Boolean { + if (!state.inString && (char == '"' || char == '\'')) { + state.inString = true + state.stringChar = char + result.append(char) + return true + } + return false + } + + private fun handleStringEnd( + char: Char, + sourceCode: String, + state: ExtractionState, + result: StringBuilder, + ): Boolean { + if (!state.inString || char != state.stringChar) { + return false + } + val isEscaped = state.index > 0 && sourceCode[state.index - 1] == '\\' + return if (!isEscaped) { + state.inString = false + state.stringChar = null + result.append(char) + true + } else { + false + } + } + + private fun handleOpeningBracket(char: Char, state: ExtractionState, result: StringBuilder): Boolean { + val bracketType = when (char) { + '(' -> '(' + '[' -> '[' + '{' -> '{' + else -> return false + } + state.depth++ + state.bracketStack.add(bracketType) + result.append(char) + return true + } + + private fun handleClosingBracket(char: Char, state: ExtractionState, result: StringBuilder): Boolean { + if (state.depth == 0) { + return true + } + val matchingBracket = when (char) { + ')' -> '(' + ']' -> '[' + '}' -> '{' + else -> null + } + val isValidMatch = matchingBracket != null && + state.bracketStack.isNotEmpty() && + state.bracketStack.last() == matchingBracket + return if (isValidMatch) { + state.bracketStack.removeAt(state.bracketStack.size - 1) + state.depth-- + result.append(char) + false + } else { + true + } + } + + private fun handleParameterSeparator(char: Char, state: ExtractionState): Boolean = char == ',' && state.depth == 0 +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt new file mode 100644 index 0000000000..9fdb304985 --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -0,0 +1,516 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.processing.CodeGenerator +import com.google.devtools.ksp.processing.Dependencies +import com.google.devtools.ksp.processing.KSPLogger +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.processing.SymbolProcessor +import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.validate +import it.unibo.alchemist.boundary.dsl.BuildDsl +import java.io.PrintWriter +import java.nio.charset.StandardCharsets + +/** + * KSP symbol processor that generates DSL builder functions for classes annotated with [BuildDsl]. + */ +class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) : SymbolProcessor { + override fun process(resolver: Resolver): List { + logger.info("DslBuilderProcessor: Starting processing") + logger.info("DslBuilderProcessor: BuildDsl qualified name: ${BuildDsl::class.qualifiedName}") + + val annotationName = BuildDsl::class.qualifiedName ?: return emptyList() + val symbols = resolver.getSymbolsWithAnnotation(annotationName) + val symbolList = symbols.toList() + logger.info("DslBuilderProcessor: Found ${symbolList.size} symbols with @BuildDsl annotation") + + symbolList.forEach { symbol -> + val qualifiedName = when (symbol) { + is KSClassDeclaration -> symbol.qualifiedName?.asString() ?: "unknown" + else -> symbol.toString() + } + logger.info("DslBuilderProcessor: Found symbol: $qualifiedName") + } + + val ret = symbolList.filter { !it.validate() }.toList() + + symbolList + .filter { it is KSClassDeclaration && it.validate() } + .forEach { classDecl -> + processClass(classDecl as KSClassDeclaration) + } + + return ret + } + + private fun shouldInjectType(injectionType: InjectionType, annotationValues: Map): Boolean = + when (injectionType) { + InjectionType.ENVIRONMENT -> annotationValues["injectEnvironment"] as? Boolean ?: true + InjectionType.GENERATOR -> annotationValues["injectGenerator"] as? Boolean ?: true + InjectionType.INCARNATION -> annotationValues["injectIncarnation"] as? Boolean ?: true + InjectionType.NODE -> annotationValues["injectNode"] as? Boolean ?: true + InjectionType.REACTION -> annotationValues["injectReaction"] as? Boolean ?: true + InjectionType.TIMEDISTRIBUTION -> true + } + + private fun processClass(classDecl: KSClassDeclaration) { + logger.info("DslBuilderProcessor: Processing class ${classDecl.simpleName.asString()}") + logger.info("DslBuilderProcessor: Class qualified name: ${classDecl.qualifiedName?.asString()}") + + val annotation = classDecl.annotations.firstOrNull { + it.shortName.asString() == "BuildDsl" + } + if (annotation == null) { + logger.warn("Class ${classDecl.simpleName.asString()} has no @BuildDsl annotation") + return + } + + val annotationValues = annotation.arguments + .mapNotNull { arg -> arg.name?.asString()?.let { it to arg.value } } + .toMap() + + val functionName = (annotationValues["functionName"] as? String)?.takeIf { it.isNotEmpty() } + ?: classDecl.simpleName.asString().replaceFirstChar { it.lowercaseChar() } + + val constructor = ConstructorFinder.findConstructor(classDecl) + if (constructor == null) { + logger.warn("Class ${classDecl.simpleName.asString()} has no usable constructor") + return + } + + val parameters = constructor.parameters + logger.info("DslBuilderProcessor: Found constructor with ${parameters.size} parameters") + parameters.forEachIndexed { index, param -> + val typeName = param.type.resolve().declaration.qualifiedName?.asString() ?: "unknown" + logger.info("DslBuilderProcessor: Parameter $index: ${param.name?.asString()} : $typeName") + } + + val injectionIndices = ParameterInjector.findInjectionIndices(parameters) + logger.info("DslBuilderProcessor: Injection indices: $injectionIndices") + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + logger.info("DslBuilderProcessor: Context type: $contextType") + val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues) + val remainingParams = parameters.filterIndexed { index, _ -> !paramsToSkip.contains(index) } + + val containingFile = classDecl.containingFile + val dependencies = if (containingFile != null) { + Dependencies(true, containingFile) + } else { + Dependencies.ALL_FILES + } + + val fileName = functionName.replaceFirstChar { it.uppercaseChar() } + "Helper" + + val file = codeGenerator.createNewFile( + dependencies = dependencies, + packageName = ProcessorConfig.GENERATED_PACKAGE, + fileName = fileName, + ) + + PrintWriter(file, true, StandardCharsets.UTF_8).use { writer -> + writeGeneratedCode( + writer, + classDecl, + functionName, + remainingParams, + parameters, + paramsToSkip, + injectionIndices, + annotationValues, + contextType, + ) + } + } + + private fun writeGeneratedCode( + writer: PrintWriter, + classDecl: KSClassDeclaration, + functionName: String, + remainingParams: List, + allParameters: List, + paramsToSkip: Set, + injectionIndices: Map, + annotationValues: Map, + contextType: ContextType, + ) { + writeFileHeader(writer, classDecl, contextType) + + val (initialTypeParamNames, initialTypeParamBounds) = TypeExtractor.extractTypeParameters(classDecl) + val typeParamNames = initialTypeParamNames.toMutableList() + val typeParamBounds = initialTypeParamBounds.toMutableList() + + val paramTypes = TypeExtractor.extractParamTypes(remainingParams, typeParamNames) + val defaultValues = DefaultValueAnalyzer.extractAllDefaultValues(remainingParams, classDecl) + val needsMapEnvironment = checkNeedsMapEnvironment(injectionIndices, allParameters) + val paramNames = TypeExtractor.extractParamNames(remainingParams) + + val (injectedParams, injectedParamNames, injectedParamTypesMap) = processInjectedParams( + injectionIndices, + annotationValues, + allParameters, + typeParamNames, + typeParamBounds, + ) + + val hasInjectedParams = injectedParams.isNotEmpty() + updateTypeParamsForInjected( + hasInjectedParams, + injectionIndices, + annotationValues, + allParameters, + typeParamNames, + typeParamBounds, + initialTypeParamNames, + initialTypeParamBounds, + ) + + addPositionImportIfNeeded(hasInjectedParams, typeParamNames, typeParamBounds, initialTypeParamBounds) + val constructorParams = writeImportsAndFunction( + writer, + typeParamBounds, + paramTypes, + defaultValues, + classDecl, + needsMapEnvironment, + injectedParamTypesMap, + allParameters, + remainingParams, + paramsToSkip, + paramNames, + injectionIndices, + injectedParamNames, + annotationValues, + typeParamNames, + contextType, + hasInjectedParams, + functionName, + classDecl.simpleName.asString(), + injectedParams, + initialTypeParamNames, + initialTypeParamBounds, + ) + + val hasNode = injectionIndices.containsKey(InjectionType.NODE) && + (annotationValues["injectNode"] as? Boolean ?: true) + val hasReaction = injectionIndices.containsKey(InjectionType.REACTION) && + (annotationValues["injectReaction"] as? Boolean ?: true) + + if (hasNode && !hasReaction) { + writePropertyContextFunction( + writer, + typeParamBounds, + paramTypes, + defaultValues, + classDecl, + needsMapEnvironment, + injectedParamTypesMap, + allParameters, + remainingParams, + paramsToSkip, + paramNames, + injectionIndices, + injectedParamNames, + annotationValues, + typeParamNames, + functionName, + classDecl.simpleName.asString(), + injectedParams, + initialTypeParamNames, + initialTypeParamBounds, + constructorParams, + ) + } + } + + private fun writeFileHeader(writer: PrintWriter, classDecl: KSClassDeclaration, contextType: ContextType) { + writer.println("@file:Suppress(\"UNCHECKED_CAST\", \"DEPRECATION\")") + writer.println("package ${ProcessorConfig.GENERATED_PACKAGE}") + writer.println() + writer.println("import ${classDecl.qualifiedName?.asString()}") + + when (contextType) { + ContextType.SIMULATION -> writer.println("import ${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}") + ContextType.DEPLOYMENT -> writer.println("import ${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}") + ContextType.PROGRAM -> { + writer.println("import ${ProcessorConfig.ContextTypes.PROGRAMS_CONTEXT}") + writer.println("import ${ProcessorConfig.ContextTypes.PROPERTIES_CONTEXT}") + } + ContextType.PROPERTY -> { + writer.println("import ${ProcessorConfig.ContextTypes.PROPERTIES_CONTEXT}") + } + } + } + + private fun checkNeedsMapEnvironment( + injectionIndices: Map, + allParameters: List, + ): Boolean { + val envParam = getEnvironmentParameter(injectionIndices, allParameters) ?: return false + val qualifiedName = getQualifiedName(envParam) + return qualifiedName.contains("MapEnvironment") + } + + private fun getEnvironmentParameter( + injectionIndices: Map, + allParameters: List, + ): com.google.devtools.ksp.symbol.KSValueParameter? { + val injectionIndicesForEnv = injectionIndices[InjectionType.ENVIRONMENT] ?: return null + return allParameters.getOrNull(injectionIndicesForEnv) + } + + private fun getQualifiedName(param: com.google.devtools.ksp.symbol.KSValueParameter): String { + val resolved = param.type.resolve() + return resolved.declaration.qualifiedName?.asString().orEmpty() + } + + private fun processInjectedParams( + injectionIndices: Map, + annotationValues: Map, + allParameters: List, + typeParamNames: MutableList, + typeParamBounds: MutableList, + ): Triple>, Map, Map> { + val injectedParams = mutableListOf>() + val injectedParamNames = mutableMapOf() + val injectedParamTypesMap = mutableMapOf() + + injectionIndices.forEach { (injectionType, index) -> + if (shouldInjectType(injectionType, annotationValues)) { + val param = allParameters[index] + val paramType = FunctionGenerator.buildContextParamType(param.type, typeParamNames, typeParamBounds) + val paramName = getInjectionParamName(injectionType) + injectedParams.add(paramName to paramType) + injectedParamNames[injectionType] = paramName + injectedParamTypesMap[injectionType] = paramType + } + } + + return Triple(injectedParams, injectedParamNames, injectedParamTypesMap) + } + + private fun getInjectionParamName(injectionType: InjectionType): String = when (injectionType) { + InjectionType.ENVIRONMENT -> "env" + InjectionType.GENERATOR -> "generator" + InjectionType.INCARNATION -> "incarnation" + InjectionType.NODE -> "node" + InjectionType.REACTION -> "reaction" + InjectionType.TIMEDISTRIBUTION -> "td" + } + + private fun updateTypeParamsForInjected( + hasInjectedParams: Boolean, + injectionIndices: Map, + annotationValues: Map, + allParameters: List, + typeParamNames: MutableList, + typeParamBounds: MutableList, + initialTypeParamNames: List, + initialTypeParamBounds: List, + ) { + if (!hasInjectedParams) { + return + } + + val newTypeParams = mutableMapOf() + + injectionIndices.forEach { (injectionType, index) -> + if (shouldInjectType(injectionType, annotationValues)) { + val param = allParameters[index] + val initialSize = typeParamNames.size + FunctionGenerator.buildContextParamType(param.type, typeParamNames, typeParamBounds) + + for (i in initialSize until typeParamNames.size) { + val newParam = typeParamNames[i] + val newBound = typeParamBounds[i] + if (!newTypeParams.containsKey(newParam)) { + newTypeParams[newParam] = newBound + } + } + } + } + + val originalTypeParams = initialTypeParamNames.toSet() + val allNewParams = typeParamNames.filter { it !in originalTypeParams } + + typeParamNames.clear() + typeParamBounds.clear() + + typeParamNames.addAll(initialTypeParamNames) + typeParamBounds.addAll(initialTypeParamBounds) + + allNewParams.forEach { param -> + if (!typeParamNames.contains(param)) { + typeParamNames.add(param) + typeParamBounds.add(newTypeParams[param] ?: param) + } + } + } + + private fun addPositionImportIfNeeded( + hasInjectedParams: Boolean, + typeParamNames: MutableList, + typeParamBounds: MutableList, + classTypeParamBounds: List, + ) { + val needsPositionImport = hasInjectedParams && !typeParamBounds.any { it.contains("Position") } + if (needsPositionImport && !typeParamNames.contains("P")) { + val classPIndex = classTypeParamBounds.indexOfFirst { it.contains("Position") } + val pBound = if (classPIndex >= 0) { + val classBound = classTypeParamBounds[classPIndex] + if (classBound.contains(":")) { + val boundPart = classBound.substringAfter(":") + "P:$boundPart" + } else { + "P: ${ProcessorConfig.POSITION_TYPE}

" + } + } else { + "P: it.unibo.alchemist.model.Position

" + } + val tIndex = typeParamNames.indexOf("T") + if (tIndex >= 0) { + typeParamNames.add(tIndex + 1, "P") + typeParamBounds.add(tIndex + 1, pBound) + } else { + if (!typeParamNames.contains("T")) { + typeParamNames.add("T") + typeParamBounds.add("T") + } + typeParamNames.add("P") + typeParamBounds.add(pBound) + } + } + } + + private fun writeImportsAndFunction( + writer: PrintWriter, + finalTypeParamBounds: List, + paramTypes: List, + defaultValues: List, + classDecl: KSClassDeclaration, + needsMapEnvironment: Boolean, + injectedParamTypesMap: Map, + allParameters: List, + remainingParams: List, + paramsToSkip: Set, + paramNames: List, + injectionIndices: Map, + injectedParamNames: Map, + annotationValues: Map, + typeParamNames: List, + contextType: ContextType, + hasInjectedParams: Boolean, + functionName: String, + className: String, + injectedParams: List>, + initialTypeParamNames: List, + initialTypeParamBounds: List, + ): List { + ImportManager.writeImports( + writer, + finalTypeParamBounds, + paramTypes, + defaultValues, + classDecl, + needsMapEnvironment, + injectedParamTypesMap.values.toList(), + ) + + val constructorParams = FunctionGenerator.buildConstructorParams( + allParameters, + remainingParams, + paramsToSkip, + paramNames, + injectionIndices, + injectedParamNames, + annotationValues, + typeParamNames, + contextType, + hasInjectedParams, + "ctx", + injectedParamTypesMap, + ) + + val functionSignature = FunctionGenerator.buildFunctionSignature( + functionName, + finalTypeParamBounds, + typeParamNames, + className, + remainingParams, + paramNames, + paramTypes, + injectedParams, + contextType, + initialTypeParamNames, + initialTypeParamBounds, + ) + + writer.println(functionSignature) + val constructorCall = FunctionGenerator.buildConstructorCall( + className, + typeParamNames, + constructorParams, + initialTypeParamNames, + ) + writer.println(" $constructorCall") + return constructorParams + } + + private fun writePropertyContextFunction( + writer: PrintWriter, + finalTypeParamBounds: List, + paramTypes: List, + defaultValues: List, + classDecl: KSClassDeclaration, + needsMapEnvironment: Boolean, + injectedParamTypesMap: Map, + allParameters: List, + remainingParams: List, + paramsToSkip: Set, + paramNames: List, + injectionIndices: Map, + injectedParamNames: Map, + annotationValues: Map, + typeParamNames: List, + functionName: String, + className: String, + injectedParams: List>, + initialTypeParamNames: List, + initialTypeParamBounds: List, + constructorParams: List, + ) { + writer.println() + + val (tParam, pParam) = TypeParameterHandler.findTAndPParams(typeParamNames, finalTypeParamBounds) + val pVariance = FunctionGenerator.extractVarianceFromBound(pParam, finalTypeParamBounds) + val tWithVariance = tParam + val pWithVariance = if (pVariance.isNotEmpty()) "$pVariance $pParam" else pParam + + val functionTypeParamString = TypeParameterHandler.buildTypeParamString(finalTypeParamBounds) + val returnType = TypeParameterHandler.buildReturnType(className, initialTypeParamNames) + val contextPart = "context(ctx: PropertiesContext<$tWithVariance, $pWithVariance>.PropertyContext) " + val functionParams = FunctionGenerator.buildFunctionParams(remainingParams, paramNames, paramTypes) + + val functionSignature = "${contextPart}fun$functionTypeParamString $functionName$functionParams: $returnType =" + writer.println(functionSignature) + + val propertyContextConstructorParams = ConstructorParamBuilder.convertToPropertyContextAccessors( + injectionIndices, + allParameters, + remainingParams, + paramsToSkip, + paramNames, + injectedParamNames, + annotationValues, + typeParamNames, + injectedParamTypesMap, + ) + val constructorCall = FunctionGenerator.buildConstructorCall( + className, + typeParamNames, + propertyContextConstructorParams, + initialTypeParamNames, + ) + writer.println(" $constructorCall") + } +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt new file mode 100644 index 0000000000..686a312bc6 --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt @@ -0,0 +1,15 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.processing.CodeGenerator +import com.google.devtools.ksp.processing.KSPLogger +import com.google.devtools.ksp.processing.SymbolProcessor +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.google.devtools.ksp.processing.SymbolProcessorProvider + +/** + * Provider for [DslBuilderProcessor] that creates instances for KSP processing. + */ +class DslBuilderProcessorProvider : SymbolProcessorProvider { + override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = + DslBuilderProcessor(environment.codeGenerator, environment.logger) +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt new file mode 100644 index 0000000000..b2e446218c --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt @@ -0,0 +1,251 @@ +package it.unibo.alchemist.boundary.dsl.processor + +/** + * Generates function signatures and constructor calls for DSL builder functions. + */ +object FunctionGenerator { + /** + * Builds the function signature for a DSL builder function. + * + * @param functionName The name of the function to generate + * @param typeParamBounds Type parameter bounds + * @param typeParamNames Type parameter names + * @param className The name of the class being constructed + * @param remainingParams Parameters that are not injected + * @param paramNames Names of the remaining parameters + * @param paramTypes Types of the remaining parameters + * @param injectedParams List of injected parameter names and types + * @param contextType The type of context (deployment or program) + * @param classTypeParamNames Type parameter names from the class declaration + * @return The complete function signature string + */ + fun buildFunctionSignature( + functionName: String, + typeParamBounds: List, + typeParamNames: List, + className: String, + remainingParams: List, + paramNames: List, + paramTypes: List, + injectedParams: List>, + contextType: ContextType, + classTypeParamNames: List = typeParamNames, + classTypeParamBounds: List = typeParamBounds, + ): String { + val (finalTypeParamNames, finalTypeParamBounds) = TypeParameterHandler.prepareTypeParams( + typeParamNames, + typeParamBounds, + injectedParams, + classTypeParamBounds, + ) + + val functionTypeParamString = TypeParameterHandler.buildTypeParamString(finalTypeParamBounds) + val returnType = TypeParameterHandler.buildReturnType(className, classTypeParamNames) + val contextPart = buildContextPart(injectedParams, contextType, finalTypeParamNames, finalTypeParamBounds) + val functionParams = buildFunctionParams(remainingParams, paramNames, paramTypes) + val receiverPart = buildReceiverPart(injectedParams, contextType) + + return "${contextPart}fun$functionTypeParamString $receiverPart$functionName$functionParams: $returnType =" + } + + private fun buildContextPart( + injectedParams: List>, + contextType: ContextType, + typeParamNames: List, + typeParamBounds: List, + ): String { + if (injectedParams.isEmpty()) { + return "" + } + + val (tParam, pParam) = TypeParameterHandler.findTAndPParams(typeParamNames, typeParamBounds) + val pVariance = extractVarianceFromBound(pParam, typeParamBounds) + val tWithVariance = tParam + val pWithVariance = if (pVariance.isNotEmpty()) "$pVariance $pParam" else pParam + val contextTypeName = when (contextType) { + ContextType.SIMULATION -> "SimulationContext<$tWithVariance, $pWithVariance>" + ContextType.DEPLOYMENT -> "DeploymentsContext<$tWithVariance, $pWithVariance>" + ContextType.PROGRAM -> "ProgramsContext<$tWithVariance, $pWithVariance>.ProgramContext" + ContextType.PROPERTY -> "PropertiesContext<$tWithVariance, $pWithVariance>.PropertyContext" + } + return "context(ctx: $contextTypeName) " + } + + fun extractVarianceFromBound(paramName: String, typeParamBounds: List): String { + val paramIndex = typeParamBounds.indexOfFirst { it.startsWith("$paramName:") } + if (paramIndex < 0) { + return "" + } + val bound = typeParamBounds[paramIndex] + val boundPart = bound.substringAfter(":", "").trim() + + val escapedParamName = Regex.escape(paramName) + val outPattern = Regex("""""") + val inPattern = Regex("""""") + + if (outPattern.containsMatchIn(boundPart)) { + return "out" + } + if (inPattern.containsMatchIn(boundPart)) { + return "in" + } + + if (boundPart.startsWith("out ")) { + return "out" + } + if (boundPart.startsWith("in ")) { + return "in" + } + return "" + } + + fun buildFunctionParams( + remainingParams: List, + paramNames: List, + paramTypes: List, + ): String { + val regularParams = remainingParams.mapIndexed { idx, param -> + val name = paramNames[idx] + val type = paramTypes[idx] + val varargKeyword = if (param.isVararg) "vararg " else "" + val defaultValue = extractDefaultValue(param) + "$varargKeyword$name: $type$defaultValue" + } + + val regularParamsPart = regularParams.joinToString(", ") + return if (regularParamsPart.isEmpty()) { + "()" + } else { + "($regularParamsPart)" + } + } + + private fun buildReceiverPart(injectedParams: List>, contextType: ContextType): String = "" + + /** + * Builds the list of constructor parameter expressions. + * + * @param allParameters All constructor parameters + * @param remainingParams Parameters that are not injected + * @param paramsToSkip Set of parameter indices to skip + * @param paramNames Names of remaining parameters + * @param injectionIndices Map of injection types to parameter indices + * @param injectedParamNames Map of injection types to parameter names + * @param annotationValues Annotation values from BuildDsl + * @param typeParamNames Type parameter names + * @param contextType The type of context + * @param hasContextParams Whether context parameters are present + * @param contextParamName Name of the context parameter + * @param injectedParamTypes Map of injection types to parameter types + * @return List of constructor parameter expressions + */ + // CPD-OFF: Function signature duplication is necessary for API delegation + fun buildConstructorParams( + allParameters: List, + remainingParams: List, + paramsToSkip: Set, + paramNames: List, + injectionIndices: Map, + injectedParamNames: Map, + annotationValues: Map, + typeParamNames: List, + contextType: ContextType, + hasContextParams: Boolean = false, + contextParamName: String = "ctx", + injectedParamTypes: Map = emptyMap(), + ): List = ConstructorParamBuilder.buildConstructorParams( + allParameters, + remainingParams, + paramsToSkip, + paramNames, + injectionIndices, + injectedParamNames, + annotationValues, + typeParamNames, + contextType, + hasContextParams, + contextParamName, + injectedParamTypes, + ) + // CPD-ON + + /** + * Builds the constructor call expression. + * + * @param className The name of the class + * @param typeParamNames Type parameter names + * @param constructorParams List of constructor parameter expressions + * @param classTypeParamNames Type parameter names from the class declaration + * @return The constructor call string + */ + fun buildConstructorCall( + className: String, + typeParamNames: List, + constructorParams: List, + classTypeParamNames: List = typeParamNames, + ): String { + val constructorTypeArgs = if (classTypeParamNames.isNotEmpty()) { + "<${classTypeParamNames.joinToString(", ")}>" + } else { + "" + } + return "$className$constructorTypeArgs(${constructorParams.joinToString(", ")})" + } + + private fun extractDefaultValue(param: com.google.devtools.ksp.symbol.KSValueParameter): String { + if (!param.hasDefault) { + return "" + } + + val defaultValueExpr = DefaultValueAnalyzer.tryExtractDefaultFromSource(param) + return defaultValueExpr?.let { " = $it" }.orEmpty() + } + + /** + * Collects type parameters needed for a type reference. + * + * @param typeRef The type reference to analyze + * @param existingTypeParamNames List of existing type parameter names + * @return Set of needed type parameter names + */ + fun collectNeededTypeParams( + typeRef: com.google.devtools.ksp.symbol.KSTypeReference, + existingTypeParamNames: List, + ): Set = TypeParameterHandler.collectNeededTypeParams(typeRef, existingTypeParamNames) + + /** + * Builds the type string for a context parameter, handling type arguments and bounds. + * + * @param typeRef The type reference to build from + * @param typeParamNames Mutable list of type parameter names (may be modified) + * @param typeParamBounds Mutable list of type parameter bounds (may be modified) + * @return The type string for the context parameter + */ + fun buildContextParamType( + typeRef: com.google.devtools.ksp.symbol.KSTypeReference, + typeParamNames: MutableList, + typeParamBounds: MutableList, + ): String = TypeArgumentProcessor.buildContextParamType(typeRef, typeParamNames, typeParamBounds) + + fun buildConstructorParamsForPropertyContext( + allParameters: List, + remainingParams: List, + paramsToSkip: Set, + paramNames: List, + injectionIndices: Map, + injectedParamNames: Map, + annotationValues: Map, + typeParamNames: List, + injectedParamTypes: Map = emptyMap(), + ): List = ConstructorParamBuilder.buildConstructorParamsForPropertyContext( + allParameters, + remainingParams, + paramsToSkip, + paramNames, + injectionIndices, + injectedParamNames, + annotationValues, + typeParamNames, + injectedParamTypes, + ) +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt new file mode 100644 index 0000000000..fa46ab5baa --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt @@ -0,0 +1,36 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSValueParameter +import java.io.PrintWriter + +/** + * Manages writing import statements for generated DSL code. + */ +object ImportManager { + /** + * Writes all necessary import statements to the generated code file. + * + * @param writer The PrintWriter to write imports to + * @param typeParamBounds Type parameter bounds that may require imports + * @param paramTypes Parameter types that may require imports + * @param defaultValues Default value expressions that may require imports + * @param classDecl The class declaration being processed + * @param needsMapEnvironment Whether MapEnvironment import is needed + * @param injectedParamTypes Types of injected parameters that may require imports + */ + fun writeImports( + writer: PrintWriter, + typeParamBounds: List, + paramTypes: List, + defaultValues: List, + classDecl: KSClassDeclaration, + needsMapEnvironment: Boolean = false, + injectedParamTypes: List = emptyList(), + ) { + val neededImports = DefaultValueAnalyzer.extractNeededImportsFromDefaults(defaultValues, classDecl) + neededImports.forEach { writer.println(it) } + + writer.println() + } +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt new file mode 100644 index 0000000000..16abcba7c1 --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -0,0 +1,265 @@ +package it.unibo.alchemist.boundary.dsl.processor + +/** + * Types of parameters that can be injected from context. + */ +enum class InjectionType { + /** Environment parameter injection. */ + ENVIRONMENT, + + /** Random generator parameter injection. */ + GENERATOR, + + /** Incarnation parameter injection. */ + INCARNATION, + + /** Node parameter injection. */ + NODE, + + /** Reaction parameter injection. */ + REACTION, + + /** Time distribution parameter injection. */ + TIMEDISTRIBUTION, +} + +/** + * Information about a parameter injection. + * + * @property type The type of injection + * @property index The parameter index + * @property inject Whether to inject this parameter + */ +data class InjectionInfo( + /** The type of injection. */ + val type: InjectionType, + /** The parameter index. */ + val index: Int, + /** Whether to inject this parameter. */ + val inject: Boolean, +) + +/** + * Finds and manages parameter injection indices for context-aware DSL generation. + */ +object ParameterInjector { + /** + * Finds indices of parameters that can be injected from context. + * + * @param parameters The list of constructor parameters to analyze + * @return A map from injection type to parameter index + */ + fun findInjectionIndices( + parameters: List, + ): Map { + val indices = mutableMapOf() + + parameters.forEachIndexed { index, param -> + val resolved = param.type.resolve() + val declaration = resolved.declaration + val qualifiedName = declaration.qualifiedName?.asString().orEmpty() + val simpleName = declaration.simpleName.asString() + + when { + isEnvironmentType(resolved, qualifiedName) -> indices[InjectionType.ENVIRONMENT] = index + isGeneratorType(resolved, qualifiedName) -> indices[InjectionType.GENERATOR] = index + isIncarnationType(resolved, qualifiedName) -> indices[InjectionType.INCARNATION] = index + isNodeType(resolved, simpleName, qualifiedName) -> indices[InjectionType.NODE] = index + isReactionType(resolved, simpleName, qualifiedName) -> indices[InjectionType.REACTION] = index + isTimeDistributionType(resolved, simpleName, qualifiedName) -> indices[InjectionType.TIMEDISTRIBUTION] = + index + } + } + + return indices + } + + private fun isEnvironmentType(type: com.google.devtools.ksp.symbol.KSType, qualifiedName: String): Boolean { + if (!qualifiedName.contains("Environment")) { + return false + } + return TypeHierarchyChecker.matchesTypeOrPackage( + type, + ProcessorConfig.ENVIRONMENT_TYPE, + ProcessorConfig.ENVIRONMENT_PACKAGE_PATTERNS, + ) + } + + private fun isGeneratorType(type: com.google.devtools.ksp.symbol.KSType, qualifiedName: String): Boolean { + if (!qualifiedName.contains("RandomGenerator")) { + return false + } + return TypeHierarchyChecker.isAssignableTo(type, ProcessorConfig.RANDOM_GENERATOR_TYPE) || + qualifiedName == ProcessorConfig.RANDOM_GENERATOR_TYPE + } + + private fun isIncarnationType(type: com.google.devtools.ksp.symbol.KSType, qualifiedName: String): Boolean { + if (!qualifiedName.contains("Incarnation")) { + return false + } + return TypeHierarchyChecker.isAssignableTo(type, ProcessorConfig.INCARNATION_TYPE) || + qualifiedName == ProcessorConfig.INCARNATION_TYPE + } + + private fun isNodeType( + type: com.google.devtools.ksp.symbol.KSType, + simpleName: String, + qualifiedName: String, + ): Boolean { + if (simpleName != "Node" && !qualifiedName.endsWith(".Node")) { + return false + } + return TypeHierarchyChecker.isAssignableTo(type, ProcessorConfig.NODE_TYPE) || + qualifiedName == ProcessorConfig.NODE_TYPE || + qualifiedName.startsWith("${ProcessorConfig.NODE_TYPE}.") + } + + private fun isReactionType( + type: com.google.devtools.ksp.symbol.KSType, + simpleName: String, + qualifiedName: String, + ): Boolean { + if (simpleName != "Reaction" && !qualifiedName.endsWith(".Reaction")) { + return false + } + return TypeHierarchyChecker.isAssignableTo(type, ProcessorConfig.REACTION_TYPE) || + qualifiedName == ProcessorConfig.REACTION_TYPE || + qualifiedName.startsWith("${ProcessorConfig.REACTION_TYPE}.") + } + + private fun isTimeDistributionType( + type: com.google.devtools.ksp.symbol.KSType, + simpleName: String, + qualifiedName: String, + ): Boolean { + if (simpleName != "TimeDistribution" && !qualifiedName.endsWith(".TimeDistribution")) { + return false + } + return TypeHierarchyChecker.isAssignableTo(type, ProcessorConfig.TIME_DISTRIBUTION_TYPE) || + qualifiedName == ProcessorConfig.TIME_DISTRIBUTION_TYPE || + qualifiedName.startsWith("${ProcessorConfig.TIME_DISTRIBUTION_TYPE}.") + } + + /** + * Determines the context type based on injection indices and annotation values. + * + * @param injectionIndices Map of injection types to parameter indices + * @param annotationValues Annotation values from the BuildDsl annotation + * @return The determined context type + */ + fun determineContextType( + injectionIndices: Map, + annotationValues: Map, + ): ContextType { + val hasNode = injectionIndices.containsKey(InjectionType.NODE) && + (annotationValues["injectNode"] as? Boolean ?: true) + val hasReaction = injectionIndices.containsKey(InjectionType.REACTION) && + (annotationValues["injectReaction"] as? Boolean ?: true) + val hasTimeDistribution = injectionIndices.containsKey(InjectionType.TIMEDISTRIBUTION) + + if (hasNode || hasReaction || hasTimeDistribution) { + return ContextType.PROGRAM + } + + val hasEnvironment = injectionIndices.containsKey(InjectionType.ENVIRONMENT) && + (annotationValues["injectEnvironment"] as? Boolean ?: true) + val hasGenerator = injectionIndices.containsKey(InjectionType.GENERATOR) && + (annotationValues["injectGenerator"] as? Boolean ?: true) + val hasIncarnation = injectionIndices.containsKey(InjectionType.INCARNATION) && + (annotationValues["injectIncarnation"] as? Boolean ?: true) + + val injectedCount = listOf(hasEnvironment, hasGenerator, hasIncarnation).count { it } + + return if (injectedCount == 1 && (hasIncarnation || hasEnvironment)) { + ContextType.SIMULATION + } else { + ContextType.DEPLOYMENT + } + } + + /** + * Gets the set of parameter indices that should be skipped (injected from context). + * + * @param injectionIndices Map of injection types to parameter indices + * @param annotationValues Annotation values from the BuildDsl annotation + * @return Set of parameter indices to skip + */ + fun getInjectionParams(injectionIndices: Map, annotationValues: Map): Set { + val paramsToSkip = mutableSetOf() + + addInjectionParamIfEnabled( + InjectionType.ENVIRONMENT, + "injectEnvironment", + injectionIndices, + annotationValues, + paramsToSkip, + ) + + addInjectionParamIfEnabled( + InjectionType.GENERATOR, + "injectGenerator", + injectionIndices, + annotationValues, + paramsToSkip, + ) + + addInjectionParamIfEnabled( + InjectionType.INCARNATION, + "injectIncarnation", + injectionIndices, + annotationValues, + paramsToSkip, + ) + + addInjectionParamIfEnabled( + InjectionType.NODE, + "injectNode", + injectionIndices, + annotationValues, + paramsToSkip, + ) + + addInjectionParamIfEnabled( + InjectionType.REACTION, + "injectReaction", + injectionIndices, + annotationValues, + paramsToSkip, + ) + + injectionIndices[InjectionType.TIMEDISTRIBUTION]?.let { paramsToSkip.add(it) } + + return paramsToSkip + } + + private fun addInjectionParamIfEnabled( + injectionType: InjectionType, + annotationKey: String, + injectionIndices: Map, + annotationValues: Map, + paramsToSkip: MutableSet, + ) { + if ((annotationValues[annotationKey] as? Boolean ?: true) && + injectionIndices.containsKey(injectionType) + ) { + injectionIndices[injectionType]?.let { paramsToSkip.add(it) } + } + } +} + +/** + * Type of context available for parameter injection. + */ +enum class ContextType { + /** Simulation context (only incarnation or only environment). */ + SIMULATION, + + /** Deployment context (environment and generator). */ + DEPLOYMENT, + + /** Program context (includes node, reaction, and time distribution). */ + PROGRAM, + + /** Property context (includes node, same depth as program context). */ + PROPERTY, +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt new file mode 100644 index 0000000000..dc3cc9b178 --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt @@ -0,0 +1,92 @@ +package it.unibo.alchemist.boundary.dsl.processor + +/** + * Configuration for the DSL processor, centralizing package names and type detection rules. + * This makes the processor more maintainable and allows for easier customization. + */ +object ProcessorConfig { + /** + * Base package for Alchemist model classes. + */ + const val MODEL_PACKAGE = "it.unibo.alchemist.model" + + /** + * Base package for Alchemist boundary DSL classes. + */ + const val DSL_PACKAGE = "it.unibo.alchemist.boundary.dsl" + + /** + * Package where generated code will be placed. + */ + const val GENERATED_PACKAGE = "$DSL_PACKAGE.generated" + + /** + * Package for DSL model classes (contexts). + */ + const val DSL_MODEL_PACKAGE = "$DSL_PACKAGE.model" + + /** + * Fully qualified name for the Position interface. + */ + const val POSITION_TYPE = "$MODEL_PACKAGE.Position" + + /** + * Fully qualified name for the Environment interface. + */ + const val ENVIRONMENT_TYPE = "$MODEL_PACKAGE.Environment" + + /** + * Fully qualified name for the Incarnation interface. + */ + const val INCARNATION_TYPE = "$MODEL_PACKAGE.Incarnation" + + /** + * Fully qualified name for the Node class. + */ + const val NODE_TYPE = "$MODEL_PACKAGE.Node" + + /** + * Fully qualified name for the Reaction interface. + */ + const val REACTION_TYPE = "$MODEL_PACKAGE.Reaction" + + /** + * Fully qualified name for the TimeDistribution interface. + */ + const val TIME_DISTRIBUTION_TYPE = "$MODEL_PACKAGE.TimeDistribution" + + /** + * Fully qualified name for RandomGenerator. + */ + const val RANDOM_GENERATOR_TYPE = "org.apache.commons.math3.random.RandomGenerator" + + /** + * Package patterns that should be considered for Environment type detection. + * This replaces the hardcoded "maps" check. + */ + val ENVIRONMENT_PACKAGE_PATTERNS = setOf( + MODEL_PACKAGE, + "$MODEL_PACKAGE.maps", + "$MODEL_PACKAGE.environments", + ) + + /** + * Context type class names. + */ + object ContextTypes { + const val SIMULATION_CONTEXT = "$DSL_MODEL_PACKAGE.SimulationContext" + const val DEPLOYMENTS_CONTEXT = "$DSL_MODEL_PACKAGE.DeploymentsContext" + const val PROGRAMS_CONTEXT = "$DSL_MODEL_PACKAGE.ProgramsContext" + const val PROPERTIES_CONTEXT = "$DSL_MODEL_PACKAGE.PropertiesContext" + } + + /** + * Checks if a qualified name matches any of the environment package patterns. + * + * @param qualifiedName The fully qualified name to check + * @return True if the name matches an environment package pattern + */ + fun isEnvironmentPackage(qualifiedName: String): Boolean = ENVIRONMENT_PACKAGE_PATTERNS.any { pattern -> + qualifiedName.startsWith(pattern) + } +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt new file mode 100644 index 0000000000..1c5aa95ca4 --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt @@ -0,0 +1,199 @@ +package it.unibo.alchemist.boundary.dsl.processor + +/** + * Processes type arguments for context parameters in DSL builder functions. + */ +object TypeArgumentProcessor { + /** + * Builds the type string for a context parameter, handling type arguments and bounds. + * + * @param typeRef The type reference to build from + * @param typeParamNames Mutable list of type parameter names (may be modified) + * @param typeParamBounds Mutable list of type parameter bounds (may be modified) + * @return The type string for the context parameter + */ + fun buildContextParamType( + typeRef: com.google.devtools.ksp.symbol.KSTypeReference, + typeParamNames: MutableList, + typeParamBounds: MutableList, + ): String { + val resolved = typeRef.resolve() + val declaration = resolved.declaration + val typeName = getTypeName(declaration) + val arguments = resolved.arguments + + if (arguments.isEmpty()) { + return typeName + } + + val declarationTypeParams = getDeclarationTypeParams(declaration) + val standardTypeParams = listOf("T", "U", "V", "W", "X", "Y", "Z") + val indexState = IndexState(0, 0) + + val typeArgs = arguments.map { arg -> + processTypeArgument( + arg, + declarationTypeParams, + standardTypeParams, + typeParamNames, + typeParamBounds, + indexState, + ) + }.joinToString(", ") + + return "$typeName<$typeArgs>" + } + + private data class IndexState(var nextStandardIndex: Int, var nextDeclParamIndex: Int) + + private fun getTypeName(declaration: com.google.devtools.ksp.symbol.KSDeclaration): String { + val qualifiedName = declaration.qualifiedName?.asString() + return if (qualifiedName != null && qualifiedName.isNotEmpty()) { + qualifiedName + } else { + declaration.simpleName.asString() + } + } + + private fun getDeclarationTypeParams( + declaration: com.google.devtools.ksp.symbol.KSDeclaration, + ): List = when (declaration) { + is com.google.devtools.ksp.symbol.KSClassDeclaration -> declaration.typeParameters + is com.google.devtools.ksp.symbol.KSTypeAlias -> declaration.typeParameters + else -> emptyList() + } + + private fun processTypeArgument( + arg: com.google.devtools.ksp.symbol.KSTypeArgument, + declarationTypeParams: List, + standardTypeParams: List, + typeParamNames: MutableList, + typeParamBounds: MutableList, + indexState: IndexState, + ): String = when { + arg.type == null || arg.variance == com.google.devtools.ksp.symbol.Variance.STAR -> { + val result = handleNullOrStarTypeArg( + declarationTypeParams, + standardTypeParams, + typeParamNames, + typeParamBounds, + indexState.nextDeclParamIndex, + indexState.nextStandardIndex, + ) + indexState.nextDeclParamIndex = result.second + indexState.nextStandardIndex = result.third + result.first + } + else -> processConcreteTypeArgument(arg, typeParamNames, typeParamBounds, standardTypeParams, indexState) + } + + private fun handleNullOrStarTypeArg( + declarationTypeParams: List, + standardTypeParams: List, + typeParamNames: MutableList, + typeParamBounds: MutableList, + nextDeclParamIndex: Int, + nextStandardIndex: Int, + ): Triple { + val (paramName, declParam) = if (nextDeclParamIndex < declarationTypeParams.size) { + val declParam = declarationTypeParams[nextDeclParamIndex] + declParam.name.asString() to declParam + } else if (nextStandardIndex < standardTypeParams.size) { + standardTypeParams[nextStandardIndex] to null + } else { + "T" to null + } + + val newNextDeclParamIndex = if (nextDeclParamIndex < declarationTypeParams.size) { + nextDeclParamIndex + 1 + } else { + nextDeclParamIndex + } + + val newNextStandardIndex = if (nextDeclParamIndex >= declarationTypeParams.size && + nextStandardIndex < standardTypeParams.size + ) { + nextStandardIndex + 1 + } else { + nextStandardIndex + } + + if (!typeParamNames.contains(paramName)) { + typeParamNames.add(paramName) + val boundStr = if (declParam != null) { + val bounds = declParam.bounds.map { bound -> + BoundProcessor.processBound(bound) + }.toList() + if (bounds.isNotEmpty()) { + "$paramName: ${bounds.joinToString(" & ")}" + } else { + paramName + } + } else { + paramName + } + typeParamBounds.add(boundStr) + } + + return Triple(paramName, newNextDeclParamIndex, newNextStandardIndex) + } + + private fun processConcreteTypeArgument( + arg: com.google.devtools.ksp.symbol.KSTypeArgument, + typeParamNames: MutableList, + typeParamBounds: MutableList, + standardTypeParams: List, + indexState: IndexState, + ): String { + val argType = arg.type ?: return "T" + val argDecl = argType.resolve().declaration + return if (argDecl is com.google.devtools.ksp.symbol.KSTypeParameter) { + addTypeParameterIfNeeded(argDecl, typeParamNames, typeParamBounds) + argDecl.name.asString() + } else { + processExtractedType(argType, typeParamNames, standardTypeParams, indexState, typeParamBounds) + } + } + + private fun addTypeParameterIfNeeded( + argDecl: com.google.devtools.ksp.symbol.KSTypeParameter, + typeParamNames: MutableList, + typeParamBounds: MutableList, + ) { + val paramName = argDecl.name.asString() + if (!typeParamNames.contains(paramName)) { + typeParamNames.add(paramName) + val bounds = argDecl.bounds.map { BoundProcessor.processBound(it) }.toList() + val boundStr = if (bounds.isNotEmpty()) { + "$paramName: ${bounds.joinToString(" & ")}" + } else { + paramName + } + typeParamBounds.add(boundStr) + } + } + + private fun processExtractedType( + typeRef: com.google.devtools.ksp.symbol.KSTypeReference, + typeParamNames: MutableList, + standardTypeParams: List, + indexState: IndexState, + typeParamBounds: MutableList, + ): String { + val extracted = TypeExtractor.extractTypeString(typeRef, typeParamNames) + return if (extracted.contains("*") || !typeParamNames.any { it in extracted }) { + val standardName = if (indexState.nextStandardIndex < standardTypeParams.size) { + standardTypeParams[indexState.nextStandardIndex++] + } else { + "T" + } + if (!typeParamNames.contains(standardName)) { + typeParamNames.add(standardName) + typeParamBounds.add(standardName) + } + standardName + } else { + extracted + } + } +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt new file mode 100644 index 0000000000..6dd76a9e7e --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt @@ -0,0 +1,129 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSDeclaration +import com.google.devtools.ksp.symbol.KSTypeArgument +import com.google.devtools.ksp.symbol.KSTypeParameter +import com.google.devtools.ksp.symbol.KSTypeReference +import com.google.devtools.ksp.symbol.KSValueParameter +import com.google.devtools.ksp.symbol.Variance + +/** + * Extracts type information from KSP symbols for code generation. + */ +object TypeExtractor { + /** + * Extracts type parameter names and bounds from a class declaration. + * + * @param classDecl The class declaration to extract type parameters from + * @return A pair of (type parameter names, type parameter bounds) + */ + fun extractTypeParameters(classDecl: KSClassDeclaration): Pair, List> { + val typeParameters = classDecl.typeParameters + val typeParamNames = typeParameters.map { it.name.asString() } + val typeParamBounds = typeParameters.map { typeParam -> + val bounds: List = typeParam.bounds.map { bound -> + BoundProcessor.processBound(bound, typeParamNames) + }.toList() + if (bounds.isNotEmpty()) { + val boundStr = bounds.joinToString(" & ") + "${typeParam.name.asString()}: $boundStr" + } else { + typeParam.name.asString() + } + } + return typeParamNames to typeParamBounds + } + + /** + * Extracts a string representation of a type reference. + * + * @param typeRef The type reference to extract + * @param typeParamNames List of existing type parameter names for substitution + * @return A string representation of the type + */ + fun extractTypeString(typeRef: KSTypeReference, typeParamNames: List = emptyList()): String { + val resolved = typeRef.resolve() + val declaration = resolved.declaration + + if (declaration is KSTypeParameter) { + val paramName = declaration.name.asString() + if (typeParamNames.contains(paramName)) { + return paramName + } + } + + val typeName = getTypeName(declaration) + val arguments = resolved.arguments + val typeString = if (arguments.isNotEmpty()) { + val typeArgs = arguments.joinToString(", ") { arg -> + formatTypeArgument(arg, typeParamNames) + } + "$typeName<$typeArgs>" + } else { + typeName + } + + return if (resolved.isMarkedNullable) { + "$typeString?" + } else { + typeString + } + } + + private fun getTypeName(declaration: KSDeclaration): String { + val qualifiedName = declaration.qualifiedName?.asString() + return if (qualifiedName != null && qualifiedName.isNotEmpty()) { + qualifiedName + } else { + declaration.simpleName.asString() + } + } + + private fun formatTypeArgument(arg: KSTypeArgument, typeParamNames: List): String = when { + arg.type == null -> "*" + arg.variance == Variance.STAR -> "*" + arg.variance == Variance.CONTRAVARIANT -> + arg.type?.let { "in ${extractTypeString(it, typeParamNames)}" } ?: "*" + arg.variance == Variance.COVARIANT -> + arg.type?.let { "out ${extractTypeString(it, typeParamNames)}" } ?: "*" + else -> arg.type?.let { extractTypeString(it, typeParamNames) } ?: "*" + } + + /** + * Extracts type strings for a list of value parameters. + * + * @param remainingParams The parameters to extract types from + * @param typeParamNames List of existing type parameter names for substitution + * @return A list of type strings + */ + fun extractParamTypes( + remainingParams: List, + typeParamNames: List = emptyList(), + ): List = remainingParams.map { param -> + if (param.isVararg) { + val resolved = param.type.resolve() + val declaration = resolved.declaration + val qualifiedName = declaration.qualifiedName?.asString().orEmpty() + if (qualifiedName == "kotlin.Array" || qualifiedName == "Array") { + resolved.arguments.firstOrNull()?.type?.let { elementType -> + extractTypeString(elementType, typeParamNames) + } ?: extractTypeString(param.type, typeParamNames) + } else { + extractTypeString(param.type, typeParamNames) + } + } else { + extractTypeString(param.type, typeParamNames) + } + } + + /** + * Extracts parameter names from a list of value parameters. + * + * @param remainingParams The parameters to extract names from + * @return A list of parameter names + */ + fun extractParamNames(remainingParams: List): List = remainingParams.map { param -> + param.name?.asString() ?: "param${remainingParams.indexOf(param)}" + } +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt new file mode 100644 index 0000000000..76c1844353 --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt @@ -0,0 +1,134 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSDeclaration +import com.google.devtools.ksp.symbol.KSType +import com.google.devtools.ksp.symbol.KSTypeReference + +/** + * Checks type hierarchies using KSP's type resolution instead of string matching. + * This provides more accurate type detection by checking actual type relationships. + */ +object TypeHierarchyChecker { + /** + * Checks if a type implements or extends a target type by qualified name. + * + * @param type The type to check + * @param targetQualifiedName The fully qualified name of the target type + * @return True if the type implements or extends the target type + */ + fun isAssignableTo(type: KSType, targetQualifiedName: String): Boolean { + val declaration = type.declaration + val typeQualifiedName = declaration.qualifiedName?.asString() + + if (typeQualifiedName == targetQualifiedName) { + return true + } + + if (declaration is KSClassDeclaration) { + return checkSuperTypes(declaration, targetQualifiedName, mutableSetOf()) + } + + return false + } + + /** + * Checks if a type reference resolves to a type that implements or extends a target type. + * + * @param typeRef The type reference to check + * @param targetQualifiedName The fully qualified name of the target type + * @return True if the type implements or extends the target type + */ + fun isAssignableTo(typeRef: KSTypeReference, targetQualifiedName: String): Boolean = try { + val resolved = typeRef.resolve() + isAssignableTo(resolved, targetQualifiedName) + } catch (e: Exception) { + false + } + + private fun checkSuperTypes( + classDecl: KSClassDeclaration, + targetQualifiedName: String, + visited: MutableSet, + ): Boolean { + val qualifiedName = classDecl.qualifiedName?.asString() ?: return false + + if (qualifiedName in visited) { + return false + } + visited.add(qualifiedName) + + if (qualifiedName == targetQualifiedName) { + return true + } + + val superTypes = classDecl.superTypes.toList() + for (superType in superTypes) { + try { + val resolved = superType.resolve() + val superDecl = resolved.declaration + + val superQualifiedName = superDecl.qualifiedName?.asString() + if (superQualifiedName == targetQualifiedName) { + return true + } + + if (superDecl is KSClassDeclaration) { + if (checkSuperTypes(superDecl, targetQualifiedName, visited)) { + return true + } + } + } catch (e: Exception) { + continue + } + } + + return false + } + + /** + * Checks if a type's qualified name matches any of the provided patterns. + * Falls back to string matching when type hierarchy checking is not possible. + * + * @param type The type to check + * @param targetQualifiedNames Set of fully qualified names to match against + * @return True if the type matches any target name + */ + fun matchesAny(type: KSType, targetQualifiedNames: Set): Boolean { + val declaration = type.declaration + val qualifiedName = declaration.qualifiedName?.asString() ?: return false + + if (targetQualifiedNames.contains(qualifiedName)) { + return true + } + + return targetQualifiedNames.any { targetName -> + isAssignableTo(type, targetName) + } + } + + /** + * Checks if a type's qualified name matches a pattern or is in a package. + * + * @param type The type to check + * @param targetQualifiedName The target qualified name + * @param packagePatterns Set of package patterns to check + * @return True if the type matches + */ + fun matchesTypeOrPackage(type: KSType, targetQualifiedName: String, packagePatterns: Set): Boolean { + val declaration = type.declaration + val qualifiedName = declaration.qualifiedName?.asString() ?: return false + + if (qualifiedName == targetQualifiedName) { + return true + } + + if (isAssignableTo(type, targetQualifiedName)) { + return true + } + + return packagePatterns.any { pattern -> + qualifiedName.startsWith(pattern) + } + } +} diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt new file mode 100644 index 0000000000..659566677d --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt @@ -0,0 +1,208 @@ +package it.unibo.alchemist.boundary.dsl.processor + +/** + * Handles type parameter preparation and manipulation for DSL builder functions. + */ +object TypeParameterHandler { + /** + * Prepares type parameters by adding T and P parameters if needed for injected parameters. + * + * @param typeParamNames Initial type parameter names + * @param typeParamBounds Initial type parameter bounds + * @param injectedParams List of injected parameter names and types + * @param classTypeParamBounds Type parameter bounds from the class declaration + * @return Pair of final type parameter names and bounds + */ + fun prepareTypeParams( + typeParamNames: List, + typeParamBounds: List, + injectedParams: List>, + classTypeParamBounds: List, + ): Pair, MutableList> { + val finalTypeParamNames = typeParamNames.toMutableList() + val finalTypeParamBounds = typeParamBounds.toMutableList() + + if (injectedParams.isNotEmpty()) { + val (tParam, pParam) = findTAndPParams(typeParamNames, typeParamBounds) + addTParamIfNeeded(tParam, finalTypeParamNames, finalTypeParamBounds) + addPParamIfNeeded(pParam, finalTypeParamNames, finalTypeParamBounds, classTypeParamBounds) + } else if (typeParamNames.isEmpty() && classTypeParamBounds.isNotEmpty()) { + finalTypeParamNames.clear() + finalTypeParamBounds.clear() + classTypeParamBounds.forEachIndexed { index, bound -> + val paramName = if (bound.contains(":")) bound.substringBefore(":") else bound + finalTypeParamNames.add(paramName.trim()) + finalTypeParamBounds.add(bound) + } + } + + return finalTypeParamNames to finalTypeParamBounds + } + + private fun addTParamIfNeeded( + tParam: String, + finalTypeParamNames: MutableList, + finalTypeParamBounds: MutableList, + ) { + val tIndex = finalTypeParamNames.indexOf(tParam) + if (tIndex >= 0) { + val existingTBound = finalTypeParamBounds.getOrNull(tIndex) + if (existingTBound != null && !existingTBound.contains(":")) { + finalTypeParamBounds[tIndex] = tParam + } + } else { + finalTypeParamNames.add(tParam) + val tBound = finalTypeParamBounds.find { it.startsWith("$tParam:") } ?: tParam + finalTypeParamBounds.add(tBound) + } + } + + private fun addPParamIfNeeded( + pParam: String, + finalTypeParamNames: MutableList, + finalTypeParamBounds: MutableList, + classTypeParamBounds: List, + ) { + val pIndex = finalTypeParamNames.indexOf(pParam) + val classPIndex = classTypeParamBounds.indexOfFirst { it.contains("Position") } + val expectedBound = if (classPIndex >= 0) { + val classBound = classTypeParamBounds[classPIndex] + if (classBound.contains(":")) { + val boundPart = classBound.substringAfter(":") + "$pParam:$boundPart" + } else { + "$pParam: ${ProcessorConfig.POSITION_TYPE}<$pParam>" + } + } else { + "$pParam: it.unibo.alchemist.model.Position<$pParam>" + } + if (pIndex >= 0) { + val existingBound = finalTypeParamBounds.getOrNull(pIndex) + if (existingBound == null || !existingBound.contains("Position") || existingBound != expectedBound) { + if (pIndex < finalTypeParamBounds.size) { + finalTypeParamBounds[pIndex] = expectedBound + } else { + finalTypeParamBounds.add(expectedBound) + } + } + } else { + finalTypeParamNames.add(pParam) + finalTypeParamBounds.add(expectedBound) + } + } + + /** + * Finds or determines the T and P type parameter names from the given lists. + * + * @param typeParamNames List of type parameter names + * @param typeParamBounds List of type parameter bounds + * @return Pair of (T parameter name, P parameter name) + */ + fun findTAndPParams(typeParamNames: List, typeParamBounds: List): Pair { + val pIndex = typeParamBounds.indexOfFirst { it.contains("Position") } + + val pParam = if (pIndex >= 0 && pIndex < typeParamNames.size) { + typeParamNames[pIndex] + } else { + "P" + } + + val tIndex = typeParamNames.indexOf("T") + val tParam = when { + tIndex >= 0 -> typeParamNames[tIndex] + pIndex == 0 && typeParamNames.size > 1 -> typeParamNames[1] + pIndex > 0 -> typeParamNames[0] + typeParamNames.size > 0 && pIndex < 0 -> typeParamNames[0] + else -> "T" + } + + return tParam to pParam + } + + /** + * Builds the type parameter string for function signatures. + * + * @param finalTypeParamBounds List of type parameter bounds + * @return Type parameter string (e.g., ">") or empty string + */ + fun buildTypeParamString(finalTypeParamBounds: List): String = if (finalTypeParamBounds.isNotEmpty()) { + "<${finalTypeParamBounds.joinToString(", ")}>" + } else { + "" + } + + /** + * Builds the return type string for function signatures. + * + * @param className The name of the class + * @param classTypeParamNames Type parameter names from the class declaration + * @return Return type string (e.g., "MyClass" or "MyClass") + */ + fun buildReturnType(className: String, classTypeParamNames: List): String = + if (classTypeParamNames.isNotEmpty()) { + "$className<${classTypeParamNames.joinToString(", ")}>" + } else { + className + } + + /** + * Collects type parameters needed for a type reference. + * + * @param typeRef The type reference to analyze + * @param existingTypeParamNames List of existing type parameter names + * @return Set of needed type parameter names + */ + fun collectNeededTypeParams( + typeRef: com.google.devtools.ksp.symbol.KSTypeReference, + existingTypeParamNames: List, + ): Set { + val needed = mutableSetOf() + val resolved = typeRef.resolve() + val arguments = resolved.arguments + + arguments.forEach { arg -> + processTypeArgForCollection(arg, existingTypeParamNames, needed) + } + + return needed + } + + private fun processTypeArgForCollection( + arg: com.google.devtools.ksp.symbol.KSTypeArgument, + existingTypeParamNames: List, + needed: MutableSet, + ) { + when { + arg.type == null || arg.variance == com.google.devtools.ksp.symbol.Variance.STAR -> { + if (existingTypeParamNames.isEmpty()) { + needed.add("T") + } + } + else -> { + processConcreteTypeArgForCollection(arg, existingTypeParamNames, needed) + } + } + } + + private fun processConcreteTypeArgForCollection( + arg: com.google.devtools.ksp.symbol.KSTypeArgument, + existingTypeParamNames: List, + needed: MutableSet, + ) { + val argType = arg.type ?: return + val argDecl = argType.resolve().declaration + if (argDecl is com.google.devtools.ksp.symbol.KSTypeParameter) { + val paramName = argDecl.name.asString() + if (!existingTypeParamNames.contains(paramName)) { + needed.add(paramName) + } + } else { + val extracted = TypeExtractor.extractTypeString(argType, existingTypeParamNames) + if ((extracted.contains("*") || !existingTypeParamNames.any { it in extracted }) && + existingTypeParamNames.isEmpty() + ) { + needed.add("T") + } + } + } +} diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt new file mode 100644 index 0000000000..1f50b39d59 --- /dev/null +++ b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt @@ -0,0 +1,68 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class ContextAccessorTest { + @Test + fun `test simulation context accessors`() { + assertEquals("ctx.environment", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.SIMULATION)) + assertEquals( + "ctx.scenarioGenerator", + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.SIMULATION), + ) + assertEquals("ctx.incarnation", ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.SIMULATION)) + } + + @Test + fun `test deployment context accessors`() { + assertEquals("ctx.env", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT)) + assertEquals("ctx.generator", ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.DEPLOYMENT)) + assertEquals( + "ctx.ctx.incarnation", + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.DEPLOYMENT), + ) + } + + @Test + fun `test program context accessors`() { + assertEquals("ctx.ctx.ctx.env", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROGRAM)) + assertEquals("ctx.ctx.ctx.generator", ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROGRAM)) + assertEquals( + "ctx.ctx.ctx.ctx.incarnation", + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.PROGRAM), + ) + assertEquals("ctx.node", ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROGRAM)) + assertEquals("ctx.reaction", ContextAccessor.getAccessor(InjectionType.REACTION, ContextType.PROGRAM)) + assertEquals( + "ctx.timeDistribution!!", + ContextAccessor.getAccessor(InjectionType.TIMEDISTRIBUTION, ContextType.PROGRAM), + ) + } + + @Test + fun `test property context accessors`() { + assertEquals("ctx.ctx.ctx.env", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROPERTY)) + assertEquals( + "ctx.ctx.ctx.generator", + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROPERTY), + ) + assertEquals( + "ctx.ctx.ctx.ctx.incarnation", + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.PROPERTY), + ) + assertEquals("ctx.node", ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROPERTY)) + } + + @Test + fun `test custom context parameter name`() { + assertEquals( + "customCtx.env", + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT, "customCtx"), + ) + assertEquals( + "customCtx.node", + ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROGRAM, "customCtx"), + ) + } +} diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt new file mode 100644 index 0000000000..013d725165 --- /dev/null +++ b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt @@ -0,0 +1,96 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class ParameterInjectorTest { + @Test + fun `test determineContextType with node and reaction`() { + val injectionIndices = mapOf( + InjectionType.NODE to 0, + InjectionType.REACTION to 1, + ) + val annotationValues = emptyMap() + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.PROGRAM, contextType) + } + + @Test + fun `test determineContextType with only environment`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = emptyMap() + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.SIMULATION, contextType) + } + + @Test + fun `test determineContextType with only incarnation`() { + val injectionIndices = mapOf( + InjectionType.INCARNATION to 0, + ) + val annotationValues = emptyMap() + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.SIMULATION, contextType) + } + + @Test + fun `test determineContextType with environment and generator`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + InjectionType.GENERATOR to 1, + ) + val annotationValues = emptyMap() + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.DEPLOYMENT, contextType) + } + + @Test + fun `test getInjectionParams with all enabled`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + InjectionType.GENERATOR to 1, + InjectionType.NODE to 2, + ) + val annotationValues = emptyMap() + + val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues) + + assertEquals(setOf(0, 1, 2), paramsToSkip) + } + + @Test + fun `test getInjectionParams with environment disabled`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + InjectionType.GENERATOR to 1, + ) + val annotationValues = mapOf("injectEnvironment" to false) + + val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues) + + assertEquals(setOf(1), paramsToSkip) + } + + @Test + fun `test getInjectionParams with time distribution always injected`() { + val injectionIndices = mapOf( + InjectionType.TIMEDISTRIBUTION to 0, + ) + val annotationValues = emptyMap() + + val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues) + + assertEquals(setOf(0), paramsToSkip) + } +} diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt new file mode 100644 index 0000000000..c17fc5346c --- /dev/null +++ b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt @@ -0,0 +1,26 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class ProcessorConfigTest { + @Test + fun `test environment package patterns`() { + assertTrue(ProcessorConfig.isEnvironmentPackage("it.unibo.alchemist.model.Environment")) + assertTrue(ProcessorConfig.isEnvironmentPackage("it.unibo.alchemist.model.maps.OSMEnvironment")) + assertTrue( + ProcessorConfig.isEnvironmentPackage("it.unibo.alchemist.model.environments.Continuous2DEnvironment"), + ) + assertTrue(!ProcessorConfig.isEnvironmentPackage("com.example.Environment")) + } + + @Test + fun `test config constants`() { + assertEquals("it.unibo.alchemist.model", ProcessorConfig.MODEL_PACKAGE) + assertEquals("it.unibo.alchemist.boundary.dsl", ProcessorConfig.DSL_PACKAGE) + assertEquals("it.unibo.alchemist.boundary.dsl.generated", ProcessorConfig.GENERATED_PACKAGE) + assertEquals("it.unibo.alchemist.model.Position", ProcessorConfig.POSITION_TYPE) + assertEquals("it.unibo.alchemist.model.Environment", ProcessorConfig.ENVIRONMENT_TYPE) + } +} diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt new file mode 100644 index 0000000000..297f66babd --- /dev/null +++ b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt @@ -0,0 +1,71 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class TypeParameterHandlerTest { + @Test + fun `test buildTypeParamString with single parameter`() { + val typeParamBounds = listOf("T") + val result = TypeParameterHandler.buildTypeParamString(typeParamBounds) + + assertEquals("", result) + } + + @Test + fun `test buildTypeParamString with multiple parameters`() { + val typeParamBounds = listOf("T", "P: it.unibo.alchemist.model.Position

") + val result = TypeParameterHandler.buildTypeParamString(typeParamBounds) + + assertEquals(">", result) + } + + @Test + fun `test buildTypeParamString with empty list`() { + val typeParamBounds = emptyList() + val result = TypeParameterHandler.buildTypeParamString(typeParamBounds) + + assertEquals("", result) + } + + @Test + fun `test buildReturnType with type parameters`() { + val className = "TestClass" + val typeParamNames = listOf("T", "P") + val result = TypeParameterHandler.buildReturnType(className, typeParamNames) + + assertEquals("TestClass", result) + } + + @Test + fun `test buildReturnType without type parameters`() { + val className = "TestClass" + val typeParamNames = emptyList() + val result = TypeParameterHandler.buildReturnType(className, typeParamNames) + + assertEquals("TestClass", result) + } + + @Test + fun `test findTAndPParams`() { + val typeParamNames = listOf("T", "P") + val typeParamBounds = listOf("T", "P: it.unibo.alchemist.model.Position

") + + val (tParam, pParam) = TypeParameterHandler.findTAndPParams(typeParamNames, typeParamBounds) + + assertEquals("T", tParam) + assertEquals("P", pParam) + } + + @Test + fun `test findTAndPParams with only T`() { + val typeParamNames = listOf("T") + val typeParamBounds = listOf("T") + + val (tParam, pParam) = TypeParameterHandler.findTAndPParams(typeParamNames, typeParamBounds) + + assertEquals("T", tParam) + assertEquals("P", pParam) + } +} diff --git a/alchemist-loading/build.gradle.kts b/alchemist-loading/build.gradle.kts index f7d25a6b9c..8f6de942a3 100644 --- a/alchemist-loading/build.gradle.kts +++ b/alchemist-loading/build.gradle.kts @@ -19,6 +19,8 @@ import Libs.incarnation */ plugins { id("kotlin-jvm-convention") + kotlin("jvm") + alias(libs.plugins.ksp) } dependencies { @@ -41,17 +43,37 @@ dependencies { implementation(libs.mongodb) implementation(libs.snakeyaml) + implementation("org.jetbrains.kotlin:kotlin-scripting-common") + implementation("org.jetbrains.kotlin:kotlin-scripting-jvm") + implementation("org.jetbrains.kotlin:kotlin-scripting-jvm-host") + // implementation(project(":")) // the script definition module + runtimeOnly(libs.groovy.jsr223) runtimeOnly(kotlin("scripting-jsr223")) runtimeOnly(libs.scala.compiler) testImplementation(alchemist("engine")) testImplementation(alchemist("maps")) + testImplementation(alchemist("test")) testImplementation(libs.appdirs) testImplementation(libs.caffeine) testImplementation(libs.embedmongo) testRuntimeOnly(incarnation("sapere")) testRuntimeOnly(incarnation("protelis")) + implementation(kotlin("script-runtime")) + + implementation(libs.ksp.api) + + ksp(project(":alchemist-dsl-processor")) +} + +kotlin { + sourceSets.main { + kotlin.srcDir("build/generated/ksp/main/kotlin") + } + sourceSets.test { + kotlin.srcDir("build/generated/ksp/test/kotlin") + } } tasks.withType { @@ -68,7 +90,9 @@ tasks.withType { compilerOptions { freeCompilerArgs.addAll( "-opt-in=kotlin.time.ExperimentalTime", + "-Xuse-fir-lt=false", ) + freeCompilerArgs.add("-Xcontext-parameters") } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt index 1e8fe6f72c..a1ea567ab7 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt @@ -9,12 +9,30 @@ package it.unibo.alchemist.boundary.properties +import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.NodeProperty +import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.properties.AbstractNodeProperty +import org.apache.commons.math3.random.RandomGenerator -class TestNodeProperty(node: Node, val s: String) : AbstractNodeProperty(node) { - override fun cloneOnNewNode(node: Node): NodeProperty = TestNodeProperty(node, s) +@BuildDsl +class TestNodeProperty>( + node: Node, + val environment: Environment, + val incarnation: Incarnation, + val rng: RandomGenerator, + val s: String, +) : AbstractNodeProperty(node) { + override fun cloneOnNewNode(node: Node): NodeProperty = TestNodeProperty( + node, + environment, + incarnation, + rng, + s, + ) override fun toString(): String = super.toString() + "($s)" } diff --git a/alchemist-test/build.gradle.kts b/alchemist-test/build.gradle.kts index 1fb653fa15..ee91298347 100644 --- a/alchemist-test/build.gradle.kts +++ b/alchemist-test/build.gradle.kts @@ -20,6 +20,7 @@ import Libs.alchemist plugins { id("kotlin-jvm-convention") + alias(libs.plugins.ksp) } dependencies { @@ -31,6 +32,8 @@ dependencies { implementation(alchemist("implementationbase")) implementation(alchemist("physics")) runtimeOnly(libs.bundles.testing.runtimeOnly) + implementation(libs.ksp) + ksp(project(":alchemist-dsl-processor")) } publishing.publications { diff --git a/buildSrc/src/main/kotlin/kotlin-jvm-convention.gradle.kts b/buildSrc/src/main/kotlin/kotlin-jvm-convention.gradle.kts index 0344280917..7f6a04b4f3 100644 --- a/buildSrc/src/main/kotlin/kotlin-jvm-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/kotlin-jvm-convention.gradle.kts @@ -50,6 +50,7 @@ java { kotlin { compilerOptions { freeCompilerArgs.add("-Xjvm-default=all") // Enable default methods in Kt interfaces + freeCompilerArgs.add("-Xcontext-parameters") // Enable context receivers } } diff --git a/buildSrc/src/main/kotlin/kotlin-multiplatform-convention.gradle.kts b/buildSrc/src/main/kotlin/kotlin-multiplatform-convention.gradle.kts index 2dbfd674d7..19695e8c43 100644 --- a/buildSrc/src/main/kotlin/kotlin-multiplatform-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/kotlin-multiplatform-convention.gradle.kts @@ -17,6 +17,7 @@ kotlin { jvm { compilerOptions { freeCompilerArgs.add("-Xjvm-default=all") // Enable default methods in Kt interfaces + freeCompilerArgs.add("-Xcontext-parameters") // Enable context receivers } } diff --git a/buildSrc/src/main/kotlin/kotlin-static-analysis-convention.gradle.kts b/buildSrc/src/main/kotlin/kotlin-static-analysis-convention.gradle.kts index 71e9819af5..fbe0d7bbb3 100644 --- a/buildSrc/src/main/kotlin/kotlin-static-analysis-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/kotlin-static-analysis-convention.gradle.kts @@ -24,8 +24,15 @@ private val kmpGenerationTasks get(): TaskCollection = tasks.matching { ta } } +private val kspTasks get(): TaskCollection = tasks.matching { task -> + task.name.startsWith("ksp") +} tasks.withType().configureEach { dependsOn(kmpGenerationTasks) + dependsOn(kspTasks) + excludeGenerated() + exclude("**/build/generated/**") + exclude("**/generated/**") } tasks.allVerificationTasks.configureEach { excludeGenerated() } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 65f7191453..cd57fba5ff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,6 +12,7 @@ junit = "6.0.2" konf = "1.1.2" kotest = "6.1.3" kotlin = "2.2.21" +ksp = "2.2.10-2.0.2" kotlinx-coroutines = "1.10.2" ktor = "3.3.3" mockito = "5.21.0" @@ -84,6 +85,8 @@ kotlin-quality-assurance-plugin = "org.danilopianini.gradle-kotlin-qa:org.danilo kotlin-react = { module = "org.jetbrains.kotlin-wrappers:kotlin-react", version.ref = "react" } kotlin-react-dom = { module = "org.jetbrains.kotlin-wrappers:kotlin-react-dom", version.ref = "react" } kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } +ksp-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" } +ksp = { module = "com.google.devtools.ksp:symbol-processing", version.ref = "ksp" } kotlinx-atomicfu-runtime = { module = "org.jetbrains.kotlin:kotlinx-atomicfu-runtime", version.ref = "kotlin" } kotlinx-serialization-json = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0" kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } @@ -171,6 +174,7 @@ graphql-client = { id = "com.apollographql.apollo3", version.ref = "apollo" } graphql-server = { id = "com.expediagroup.graphql", version.ref = "graphql" } hugo = "io.github.fstaudt.hugo:0.12.0" kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } ktor = { id = "io.ktor.plugin", version.ref = "ktor" } multiJvmTesting = "org.danilopianini.multi-jvm-test-plugin:4.3.2" publishOnCentral = "org.danilopianini.publish-on-central:9.1.12" diff --git a/settings.gradle.kts b/settings.gradle.kts index f120f87f14..2d9de93466 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,6 +16,7 @@ include( "alchemist-api", "alchemist-composeui", "alchemist-cognitive-agents", + "alchemist-dsl-processor", "alchemist-engine", "alchemist-euclidean-geometry", "alchemist-full", From 597becc2bd8941d02c0c5a9b8fd1a992915dfbbb Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 8 Nov 2025 16:43:57 +0100 Subject: [PATCH 029/196] feat!: add ksp function helpers generator add @BuildDsl annotation to automatically generate helper functions --- .../src/test/java/it/unibo/alchemist/model/nodes/TestNode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java index fa3520f9e0..2a6cc3a6b4 100644 --- a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java +++ b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java @@ -9,6 +9,7 @@ package it.unibo.alchemist.model.nodes; +import it.unibo.alchemist.boundary.dsl.BuildDsl; import it.unibo.alchemist.model.Environment; import java.io.Serial; @@ -16,6 +17,7 @@ /** * Generic node for testing purposes. */ +@BuildDsl public final class TestNode extends GenericNode { @Serial From b0c71f891bf092d9ff22684fb9dcf6ba51034894 Mon Sep 17 00:00:00 2001 From: marco Date: Sat, 8 Nov 2025 16:56:12 +0100 Subject: [PATCH 030/196] feat: add @BuildDsl to some classes --- .../alchemist/model/timedistributions/ExponentialTime.java | 2 ++ .../main/java/it/unibo/alchemist/model/deployments/Circle.java | 2 ++ .../alchemist/model/deployments/GeometricGradientRectangle.java | 2 ++ .../main/java/it/unibo/alchemist/model/deployments/Point.java | 2 ++ .../java/it/unibo/alchemist/model/deployments/Rectangle.java | 2 ++ .../java/it/unibo/alchemist/model/positionfilters/Circle.java | 2 ++ .../it/unibo/alchemist/model/positionfilters/Rectangle.java | 2 ++ .../it/unibo/alchemist/boundary/extractors/MoleculeReader.kt | 2 ++ .../kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt | 2 ++ .../unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt | 2 ++ .../unibo/alchemist/model/deployments/GraphStreamDeployment.kt | 2 ++ .../main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt | 2 ++ .../main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt | 2 ++ .../it/unibo/alchemist/model/deployments/SpecificPositions.kt | 2 ++ .../main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt | 1 - 15 files changed, 28 insertions(+), 1 deletion(-) diff --git a/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java b/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java index b9104d95e1..634a426bb4 100644 --- a/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java +++ b/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java @@ -10,6 +10,7 @@ package it.unibo.alchemist.model.timedistributions; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import it.unibo.alchemist.boundary.dsl.BuildDsl; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Node; import it.unibo.alchemist.model.Time; @@ -25,6 +26,7 @@ * * @param concentration type */ +@BuildDsl public class ExponentialTime extends AbstractDistribution { @Serial diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java index 8d34438e40..6e080f1629 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java @@ -9,6 +9,7 @@ package it.unibo.alchemist.model.deployments; +import it.unibo.alchemist.boundary.dsl.BuildDsl; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; import org.apache.commons.math3.random.RandomGenerator; @@ -23,6 +24,7 @@ /** * @param

{@link Position} type */ +@BuildDsl public final class Circle

> extends AbstractRandomDeployment

{ private final double centerX; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java index aee38e8ea6..c1fa9f85e7 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java @@ -9,6 +9,7 @@ package it.unibo.alchemist.model.deployments; +import it.unibo.alchemist.boundary.dsl.BuildDsl; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; import org.apache.commons.math3.distribution.ExponentialDistribution; @@ -22,6 +23,7 @@ * * @param

position type */ +@BuildDsl public final class GeometricGradientRectangle

> extends Rectangle

{ private final ExponentialDistribution exp; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java index d4f6fa7bd2..2d81b080e2 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java @@ -9,6 +9,7 @@ package it.unibo.alchemist.model.deployments; +import it.unibo.alchemist.boundary.dsl.BuildDsl; import it.unibo.alchemist.model.Deployment; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; @@ -21,6 +22,7 @@ * * @param

position type */ +@BuildDsl public final class Point

> implements Deployment

{ private final double x; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java index 50f4d2f6fb..5ea0352c2e 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java @@ -9,6 +9,7 @@ package it.unibo.alchemist.model.deployments; +import it.unibo.alchemist.boundary.dsl.BuildDsl; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; import org.apache.commons.math3.random.RandomGenerator; @@ -18,6 +19,7 @@ /** * @param

position type */ +@BuildDsl public class Rectangle

> extends AbstractRandomDeployment

{ private final double x; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java index 785cf8d116..54c78818e6 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java @@ -9,6 +9,7 @@ package it.unibo.alchemist.model.positionfilters; +import it.unibo.alchemist.boundary.dsl.BuildDsl; import it.unibo.alchemist.model.Position2D; import java.awt.geom.Ellipse2D; @@ -18,6 +19,7 @@ * * @param

Position type */ +@BuildDsl(functionName = "CircleFilter") public class Circle

> extends Abstract2DShape

{ /** diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java index 96685b2726..be334feefb 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java @@ -9,6 +9,7 @@ package it.unibo.alchemist.model.positionfilters; +import it.unibo.alchemist.boundary.dsl.BuildDsl; import it.unibo.alchemist.model.Position2D; import java.awt.geom.Rectangle2D; @@ -21,6 +22,7 @@ * * @param

position type */ +@BuildDsl(functionName = "RectangleFilter") public class Rectangle

> extends Abstract2DShape

{ /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt index 5325f61a0e..a4901551b9 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt @@ -10,6 +10,7 @@ package it.unibo.alchemist.boundary.extractors import it.unibo.alchemist.boundary.ExportFilter +import it.unibo.alchemist.boundary.dsl.BuildDsl import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation @@ -34,6 +35,7 @@ import kotlin.math.min * aggregating data. If an empty list is passed, then the values * will be logged indipendently for each node. */ +@BuildDsl class MoleculeReader @JvmOverloads constructor( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt index 988d74fb83..8e585bf1a0 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt @@ -1,5 +1,6 @@ package it.unibo.alchemist.model.deployments +import it.unibo.alchemist.boundary.dsl.BuildDsl import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position2D @@ -20,6 +21,7 @@ import org.apache.commons.math3.random.RandomGenerator * * Default values generate a uniform deployment on a circumference. */ +@BuildDsl data class CircularArc

> @JvmOverloads constructor( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt index 3c7de791cc..da3781226d 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt @@ -9,6 +9,7 @@ package it.unibo.alchemist.model.deployments +import it.unibo.alchemist.boundary.dsl.BuildDsl import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Position @@ -19,6 +20,7 @@ import org.apache.commons.math3.random.RandomGenerator * in the proximity of those already included in the environment. * Behaviour if there are no nodes already inserted is undefined. */ +@BuildDsl class CloseToAlreadyDeployed>( randomGenerator: RandomGenerator, environment: Environment, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt index 85f85a0afd..9b13705a51 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt @@ -9,6 +9,7 @@ package it.unibo.alchemist.model.deployments +import it.unibo.alchemist.boundary.dsl.BuildDsl import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.LinkingRule @@ -19,6 +20,7 @@ import org.apache.commons.math3.random.RandomGenerator /** * A deployment based on a [GraphStream](https://github.com/graphstream) graph. */ +@BuildDsl class GraphStreamDeployment

( private val createLinks: Boolean, private val graphStreamSupport: GraphStreamSupport<*, P>, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt index 7808f7530f..578d8e1703 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt @@ -8,6 +8,7 @@ */ package it.unibo.alchemist.model.deployments +import it.unibo.alchemist.boundary.dsl.BuildDsl import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position @@ -45,6 +46,7 @@ import org.apache.commons.math3.random.RandomGenerator * @param yShift * how shifted should be positions along columns */ +@BuildDsl open class Grid @JvmOverloads constructor( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt index 1016f7c7a2..1a7b59e34b 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt @@ -9,6 +9,7 @@ package it.unibo.alchemist.model.deployments +import it.unibo.alchemist.boundary.dsl.BuildDsl import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Position2D @@ -33,6 +34,7 @@ private typealias Point2D = Pair * undefined. There polygon is closed automatically (there is no need to pass the first point also as last element). * */ +@BuildDsl open class Polygon

>( environment: Environment<*, P>, randomGenerator: RandomGenerator, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt index 857c24a4be..559ec7b9c5 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt @@ -7,6 +7,7 @@ */ package it.unibo.alchemist.model.deployments +import it.unibo.alchemist.boundary.dsl.BuildDsl import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position @@ -14,6 +15,7 @@ import it.unibo.alchemist.model.Position /** * Given an environment and a list of list of numbers, it creates a list of the right position type for the environment. */ +@BuildDsl class SpecificPositions(environment: Environment<*, *>, vararg positions: Iterable) : Deployment> { private val positions: List> = positions.map { environment.makePosition(*it.toList().toTypedArray()) } diff --git a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt index daca33f6a1..c3afe4a746 100644 --- a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt +++ b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt @@ -19,7 +19,6 @@ import it.unibo.alchemist.model.Time import it.unibo.alchemist.model.TimeDistribution import org.danilopianini.util.ListSet import org.danilopianini.util.ListSets - class GlobalTestReaction(override val timeDistribution: TimeDistribution, val environment: Environment) : GlobalReaction { override fun compareTo(other: Actionable): Int = tau.compareTo(other.tau) From ca75361359d66a9f6a67043a2f51bde0ef9d5dbd Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 10 Nov 2025 22:24:46 +0100 Subject: [PATCH 031/196] refactor: better code organization --- .../boundary/dsl/processor/BoundProcessor.kt | 13 +- .../dsl/processor/ConstructorParamBuilder.kt | 3 +- .../boundary/dsl/processor/ContextAccessor.kt | 12 +- .../dsl/processor/DslBuilderProcessor.kt | 32 +- .../dsl/processor/FunctionGenerator.kt | 35 ++- .../dsl/processor/ParameterInjector.kt | 6 +- .../boundary/dsl/processor/ProcessorConfig.kt | 2 + .../dsl/processor/TypeArgumentProcessor.kt | 10 +- .../dsl/processor/TypeHierarchyChecker.kt | 1 - .../dsl/processor/TypeParameterHandler.kt | 20 +- alchemist-loading/build.gradle.kts | 2 - .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 9 +- .../boundary/dsl/SingleUseDslLoader.kt | 4 +- ...ncarnation.kt => AvailableIncarnations.kt} | 2 +- .../boundary/dsl/model/DeploymentContext.kt | 292 +++++++++++++++++ ...tsContext.kt => DeploymentsContextImpl.kt} | 86 ++--- .../boundary/dsl/model/ExporterContext.kt | 61 +++- .../boundary/dsl/model/ExporterContextImpl.kt | 33 ++ .../boundary/dsl/model/LayerContext.kt | 45 ++- .../boundary/dsl/model/LayerContextImpl.kt | 25 ++ .../boundary/dsl/model/ProgramsContext.kt | 294 ++++++++++-------- .../boundary/dsl/model/ProgramsContextImpl.kt | 147 +++++++++ .../boundary/dsl/model/PropertiesContext.kt | 157 ++++++---- .../dsl/model/PropertiesContextImpl.kt | 73 +++++ .../boundary/dsl/model/SimulationContext.kt | 250 ++++++++------- .../dsl/model/SimulationContextImpl.kt | 131 ++++++++ .../boundary/dsl/scripting/AlchemistScript.kt | 86 +++-- .../modelproviders/KotlinDslProvider.kt | 19 +- .../resources/alchemist-default-imports.json | 41 --- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 12 +- .../it/unibo/alchemist/dsl/TestContents.kt | 4 +- .../it/unibo/alchemist/dsl/TestDeployments.kt | 16 +- .../it/unibo/alchemist/dsl/TestSimulations.kt | 2 +- .../it/unibo/alchemist/dsl/TestVariables.kt | 14 +- .../dsl/kts/11-monitors.alchemist.kts | 2 - 35 files changed, 1376 insertions(+), 565 deletions(-) rename alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/{Incarnation.kt => AvailableIncarnations.kt} (95%) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt rename alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/{DeploymentsContext.kt => DeploymentsContextImpl.kt} (70%) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContextImpl.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt delete mode 100644 alchemist-loading/src/main/resources/alchemist-default-imports.json diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt index 9b5f5922d7..4fd8d795e0 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt @@ -1,6 +1,8 @@ package it.unibo.alchemist.boundary.dsl.processor +import com.google.devtools.ksp.symbol.KSTypeArgument import com.google.devtools.ksp.symbol.KSTypeReference +import com.google.devtools.ksp.symbol.Variance /** * Processes type bounds for type parameters, cleaning up internal Kotlin type representations. @@ -38,20 +40,17 @@ object BoundProcessor { return replaceClassTypeParamReferences(result, classTypeParamNames) } - private fun formatTypeArgument( - arg: com.google.devtools.ksp.symbol.KSTypeArgument, - classTypeParamNames: List, - ): String = when { + private fun formatTypeArgument(arg: KSTypeArgument, classTypeParamNames: List): String = when { arg.type == null -> "*" - arg.variance == com.google.devtools.ksp.symbol.Variance.STAR -> "*" - arg.variance == com.google.devtools.ksp.symbol.Variance.CONTRAVARIANT -> { + arg.variance == Variance.STAR -> "*" + arg.variance == Variance.CONTRAVARIANT -> { arg.type?.let { val typeStr = TypeExtractor.extractTypeString(it, emptyList()) val replaced = replaceClassTypeParamReferences(typeStr, classTypeParamNames) "in $replaced" } ?: "*" } - arg.variance == com.google.devtools.ksp.symbol.Variance.COVARIANT -> { + arg.variance == Variance.COVARIANT -> { arg.type?.let { val typeStr = TypeExtractor.extractTypeString(it, emptyList()) val replaced = replaceClassTypeParamReferences(typeStr, classTypeParamNames) diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 79d309d9ef..7f59803cce 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -1,5 +1,6 @@ package it.unibo.alchemist.boundary.dsl.processor +import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter /** @@ -105,7 +106,7 @@ object ConstructorParamBuilder { } private fun needsCast( - constructorParamType: com.google.devtools.ksp.symbol.KSTypeReference, + constructorParamType: KSTypeReference, contextParamType: String, typeParamNames: List, ): Boolean { diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt index 11d6c8718a..afd5e3cc23 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt @@ -46,9 +46,9 @@ object ContextAccessor { private fun getProgramAccessor(injectionType: InjectionType, contextParamName: String): String = when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.env" - InjectionType.GENERATOR -> "$contextParamName.ctx.ctx.generator" - InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.ctx.incarnation" + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.ctx.env" + InjectionType.GENERATOR -> "$contextParamName.ctx.ctx.ctx.generator" + InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.ctx.ctx.incarnation" InjectionType.NODE -> "$contextParamName.node" InjectionType.REACTION -> "$contextParamName.reaction" InjectionType.TIMEDISTRIBUTION -> "$contextParamName.timeDistribution!!" @@ -56,9 +56,9 @@ object ContextAccessor { private fun getPropertyAccessor(injectionType: InjectionType, contextParamName: String): String = when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.env" - InjectionType.GENERATOR -> "$contextParamName.ctx.ctx.generator" - InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.ctx.incarnation" + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.ctx.env" + InjectionType.GENERATOR -> "$contextParamName.ctx.ctx.ctx.generator" + InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.ctx.ctx.incarnation" InjectionType.NODE -> "$contextParamName.node" InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in PropertyContext") InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 9fdb304985..5ccd3c0835 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -7,6 +7,7 @@ import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.processing.SymbolProcessor import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSValueParameter import com.google.devtools.ksp.validate import it.unibo.alchemist.boundary.dsl.BuildDsl import java.io.PrintWriter @@ -127,8 +128,8 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val writer: PrintWriter, classDecl: KSClassDeclaration, functionName: String, - remainingParams: List, - allParameters: List, + remainingParams: List, + allParameters: List, paramsToSkip: Set, injectionIndices: Map, annotationValues: Map, @@ -233,18 +234,18 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val ContextType.SIMULATION -> writer.println("import ${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}") ContextType.DEPLOYMENT -> writer.println("import ${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}") ContextType.PROGRAM -> { - writer.println("import ${ProcessorConfig.ContextTypes.PROGRAMS_CONTEXT}") + writer.println("import ${ProcessorConfig.ContextTypes.PROGRAM_CONTEXT}") writer.println("import ${ProcessorConfig.ContextTypes.PROPERTIES_CONTEXT}") } ContextType.PROPERTY -> { - writer.println("import ${ProcessorConfig.ContextTypes.PROPERTIES_CONTEXT}") + writer.println("import ${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}") } } } private fun checkNeedsMapEnvironment( injectionIndices: Map, - allParameters: List, + allParameters: List, ): Boolean { val envParam = getEnvironmentParameter(injectionIndices, allParameters) ?: return false val qualifiedName = getQualifiedName(envParam) @@ -253,13 +254,13 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val private fun getEnvironmentParameter( injectionIndices: Map, - allParameters: List, - ): com.google.devtools.ksp.symbol.KSValueParameter? { + allParameters: List, + ): KSValueParameter? { val injectionIndicesForEnv = injectionIndices[InjectionType.ENVIRONMENT] ?: return null return allParameters.getOrNull(injectionIndicesForEnv) } - private fun getQualifiedName(param: com.google.devtools.ksp.symbol.KSValueParameter): String { + private fun getQualifiedName(param: KSValueParameter): String { val resolved = param.type.resolve() return resolved.declaration.qualifiedName?.asString().orEmpty() } @@ -267,7 +268,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val private fun processInjectedParams( injectionIndices: Map, annotationValues: Map, - allParameters: List, + allParameters: List, typeParamNames: MutableList, typeParamBounds: MutableList, ): Triple>, Map, Map> { @@ -302,7 +303,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val hasInjectedParams: Boolean, injectionIndices: Map, annotationValues: Map, - allParameters: List, + allParameters: List, typeParamNames: MutableList, typeParamBounds: MutableList, initialTypeParamNames: List, @@ -390,8 +391,8 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val classDecl: KSClassDeclaration, needsMapEnvironment: Boolean, injectedParamTypesMap: Map, - allParameters: List, - remainingParams: List, + allParameters: List, + remainingParams: List, paramsToSkip: Set, paramNames: List, injectionIndices: Map, @@ -464,8 +465,8 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val classDecl: KSClassDeclaration, needsMapEnvironment: Boolean, injectedParamTypesMap: Map, - allParameters: List, - remainingParams: List, + allParameters: List, + remainingParams: List, paramsToSkip: Set, paramNames: List, injectionIndices: Map, @@ -483,12 +484,11 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val val (tParam, pParam) = TypeParameterHandler.findTAndPParams(typeParamNames, finalTypeParamBounds) val pVariance = FunctionGenerator.extractVarianceFromBound(pParam, finalTypeParamBounds) - val tWithVariance = tParam val pWithVariance = if (pVariance.isNotEmpty()) "$pVariance $pParam" else pParam val functionTypeParamString = TypeParameterHandler.buildTypeParamString(finalTypeParamBounds) val returnType = TypeParameterHandler.buildReturnType(className, initialTypeParamNames) - val contextPart = "context(ctx: PropertiesContext<$tWithVariance, $pWithVariance>.PropertyContext) " + val contextPart = "context(ctx: ${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}<$tParam, $pWithVariance>) " val functionParams = FunctionGenerator.buildFunctionParams(remainingParams, paramNames, paramTypes) val functionSignature = "${contextPart}fun$functionTypeParamString $functionName$functionParams: $returnType =" diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt index b2e446218c..ccbab0876e 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt @@ -1,5 +1,8 @@ package it.unibo.alchemist.boundary.dsl.processor +import com.google.devtools.ksp.symbol.KSTypeReference +import com.google.devtools.ksp.symbol.KSValueParameter + /** * Generates function signatures and constructor calls for DSL builder functions. */ @@ -24,7 +27,7 @@ object FunctionGenerator { typeParamBounds: List, typeParamNames: List, className: String, - remainingParams: List, + remainingParams: List, paramNames: List, paramTypes: List, injectedParams: List>, @@ -63,10 +66,12 @@ object FunctionGenerator { val tWithVariance = tParam val pWithVariance = if (pVariance.isNotEmpty()) "$pVariance $pParam" else pParam val contextTypeName = when (contextType) { - ContextType.SIMULATION -> "SimulationContext<$tWithVariance, $pWithVariance>" - ContextType.DEPLOYMENT -> "DeploymentsContext<$tWithVariance, $pWithVariance>" - ContextType.PROGRAM -> "ProgramsContext<$tWithVariance, $pWithVariance>.ProgramContext" - ContextType.PROPERTY -> "PropertiesContext<$tWithVariance, $pWithVariance>.PropertyContext" + ContextType.SIMULATION -> + "${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}<$tWithVariance, $pWithVariance>" + ContextType.DEPLOYMENT -> + "${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}<$tWithVariance, $pWithVariance>" + ContextType.PROGRAM -> "${ProcessorConfig.ContextTypes.PROGRAM_CONTEXT}<$tWithVariance, $pWithVariance>" + ContextType.PROPERTY -> "${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}<$tWithVariance, $pWithVariance>" } return "context(ctx: $contextTypeName) " } @@ -100,7 +105,7 @@ object FunctionGenerator { } fun buildFunctionParams( - remainingParams: List, + remainingParams: List, paramNames: List, paramTypes: List, ): String { @@ -141,8 +146,8 @@ object FunctionGenerator { */ // CPD-OFF: Function signature duplication is necessary for API delegation fun buildConstructorParams( - allParameters: List, - remainingParams: List, + allParameters: List, + remainingParams: List, paramsToSkip: Set, paramNames: List, injectionIndices: Map, @@ -192,7 +197,7 @@ object FunctionGenerator { return "$className$constructorTypeArgs(${constructorParams.joinToString(", ")})" } - private fun extractDefaultValue(param: com.google.devtools.ksp.symbol.KSValueParameter): String { + private fun extractDefaultValue(param: KSValueParameter): String { if (!param.hasDefault) { return "" } @@ -208,10 +213,8 @@ object FunctionGenerator { * @param existingTypeParamNames List of existing type parameter names * @return Set of needed type parameter names */ - fun collectNeededTypeParams( - typeRef: com.google.devtools.ksp.symbol.KSTypeReference, - existingTypeParamNames: List, - ): Set = TypeParameterHandler.collectNeededTypeParams(typeRef, existingTypeParamNames) + fun collectNeededTypeParams(typeRef: KSTypeReference, existingTypeParamNames: List): Set = + TypeParameterHandler.collectNeededTypeParams(typeRef, existingTypeParamNames) /** * Builds the type string for a context parameter, handling type arguments and bounds. @@ -222,14 +225,14 @@ object FunctionGenerator { * @return The type string for the context parameter */ fun buildContextParamType( - typeRef: com.google.devtools.ksp.symbol.KSTypeReference, + typeRef: KSTypeReference, typeParamNames: MutableList, typeParamBounds: MutableList, ): String = TypeArgumentProcessor.buildContextParamType(typeRef, typeParamNames, typeParamBounds) fun buildConstructorParamsForPropertyContext( - allParameters: List, - remainingParams: List, + allParameters: List, + remainingParams: List, paramsToSkip: Set, paramNames: List, injectionIndices: Map, diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index 16abcba7c1..c6eaf24643 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -1,5 +1,7 @@ package it.unibo.alchemist.boundary.dsl.processor +import com.google.devtools.ksp.symbol.KSValueParameter + /** * Types of parameters that can be injected from context. */ @@ -49,9 +51,7 @@ object ParameterInjector { * @param parameters The list of constructor parameters to analyze * @return A map from injection type to parameter index */ - fun findInjectionIndices( - parameters: List, - ): Map { + fun findInjectionIndices(parameters: List): Map { val indices = mutableMapOf() parameters.forEachIndexed { index, param -> diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt index dc3cc9b178..431e1f722c 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt @@ -77,7 +77,9 @@ object ProcessorConfig { const val SIMULATION_CONTEXT = "$DSL_MODEL_PACKAGE.SimulationContext" const val DEPLOYMENTS_CONTEXT = "$DSL_MODEL_PACKAGE.DeploymentsContext" const val PROGRAMS_CONTEXT = "$DSL_MODEL_PACKAGE.ProgramsContext" + const val PROGRAM_CONTEXT = "$DSL_MODEL_PACKAGE.ProgramContext" const val PROPERTIES_CONTEXT = "$DSL_MODEL_PACKAGE.PropertiesContext" + const val PROPERTY_CONTEXT = "$DSL_MODEL_PACKAGE.PropertyContext" } /** diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt index 1c5aa95ca4..4a80d2a5e0 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt @@ -1,5 +1,7 @@ package it.unibo.alchemist.boundary.dsl.processor +import com.google.devtools.ksp.symbol.KSTypeReference + /** * Processes type arguments for context parameters in DSL builder functions. */ @@ -13,7 +15,7 @@ object TypeArgumentProcessor { * @return The type string for the context parameter */ fun buildContextParamType( - typeRef: com.google.devtools.ksp.symbol.KSTypeReference, + typeRef: KSTypeReference, typeParamNames: MutableList, typeParamBounds: MutableList, ): String { @@ -30,7 +32,7 @@ object TypeArgumentProcessor { val standardTypeParams = listOf("T", "U", "V", "W", "X", "Y", "Z") val indexState = IndexState(0, 0) - val typeArgs = arguments.map { arg -> + val typeArgs = arguments.joinToString(", ") { arg -> processTypeArgument( arg, declarationTypeParams, @@ -39,7 +41,7 @@ object TypeArgumentProcessor { typeParamBounds, indexState, ) - }.joinToString(", ") + } return "$typeName<$typeArgs>" } @@ -174,7 +176,7 @@ object TypeArgumentProcessor { } private fun processExtractedType( - typeRef: com.google.devtools.ksp.symbol.KSTypeReference, + typeRef: KSTypeReference, typeParamNames: MutableList, standardTypeParams: List, indexState: IndexState, diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt index 76c1844353..751115ab37 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt @@ -1,7 +1,6 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSDeclaration import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSTypeReference diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt index 659566677d..d195cf13a6 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt @@ -1,5 +1,10 @@ package it.unibo.alchemist.boundary.dsl.processor +import com.google.devtools.ksp.symbol.KSTypeArgument +import com.google.devtools.ksp.symbol.KSTypeParameter +import com.google.devtools.ksp.symbol.KSTypeReference +import com.google.devtools.ksp.symbol.Variance + /** * Handles type parameter preparation and manipulation for DSL builder functions. */ @@ -112,7 +117,7 @@ object TypeParameterHandler { tIndex >= 0 -> typeParamNames[tIndex] pIndex == 0 && typeParamNames.size > 1 -> typeParamNames[1] pIndex > 0 -> typeParamNames[0] - typeParamNames.size > 0 && pIndex < 0 -> typeParamNames[0] + typeParamNames.isNotEmpty() && pIndex < 0 -> typeParamNames[0] else -> "T" } @@ -152,10 +157,7 @@ object TypeParameterHandler { * @param existingTypeParamNames List of existing type parameter names * @return Set of needed type parameter names */ - fun collectNeededTypeParams( - typeRef: com.google.devtools.ksp.symbol.KSTypeReference, - existingTypeParamNames: List, - ): Set { + fun collectNeededTypeParams(typeRef: KSTypeReference, existingTypeParamNames: List): Set { val needed = mutableSetOf() val resolved = typeRef.resolve() val arguments = resolved.arguments @@ -168,12 +170,12 @@ object TypeParameterHandler { } private fun processTypeArgForCollection( - arg: com.google.devtools.ksp.symbol.KSTypeArgument, + arg: KSTypeArgument, existingTypeParamNames: List, needed: MutableSet, ) { when { - arg.type == null || arg.variance == com.google.devtools.ksp.symbol.Variance.STAR -> { + arg.type == null || arg.variance == Variance.STAR -> { if (existingTypeParamNames.isEmpty()) { needed.add("T") } @@ -185,13 +187,13 @@ object TypeParameterHandler { } private fun processConcreteTypeArgForCollection( - arg: com.google.devtools.ksp.symbol.KSTypeArgument, + arg: KSTypeArgument, existingTypeParamNames: List, needed: MutableSet, ) { val argType = arg.type ?: return val argDecl = argType.resolve().declaration - if (argDecl is com.google.devtools.ksp.symbol.KSTypeParameter) { + if (argDecl is KSTypeParameter) { val paramName = argDecl.name.asString() if (!existingTypeParamNames.contains(paramName)) { needed.add(paramName) diff --git a/alchemist-loading/build.gradle.kts b/alchemist-loading/build.gradle.kts index 8f6de942a3..5c0dee62e6 100644 --- a/alchemist-loading/build.gradle.kts +++ b/alchemist-loading/build.gradle.kts @@ -62,8 +62,6 @@ dependencies { testRuntimeOnly(incarnation("protelis")) implementation(kotlin("script-runtime")) - implementation(libs.ksp.api) - ksp(project(":alchemist-dsl-processor")) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index a74f050972..b813c65c5a 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -13,8 +13,9 @@ import it.unibo.alchemist.boundary.DependentVariable import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.model.Incarnation as Inc +import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations as Inc import it.unibo.alchemist.boundary.dsl.model.SimulationContext +import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Position @@ -33,7 +34,7 @@ object Dsl { * @param dsl The simulation context. * @return A loader instance. */ - fun > createLoader(dsl: SimulationContext): Loader = object : SingleUseDslLoader(dsl) { + fun > createLoader(dsl: SimulationContextImpl): Loader = object : SingleUseDslLoader(dsl) { override val constants: Map = emptyMap() // not needed override val dependentVariables: Map> = emptyMap() // not needed override val variables: Map> = dsl.variablesContext.variables @@ -64,7 +65,7 @@ object Dsl { environment: Environment, block: SimulationContext.() -> Unit, ): Loader { - val ctx = SimulationContext(incarnation, environment) + val ctx = SimulationContextImpl(incarnation, environment) @Suppress("UNCHECKED_CAST") context(ctx.environment as Environment<*, *>, ctx.incarnation as Incarnation<*, *>) { ctx.apply(block) @@ -85,7 +86,7 @@ object Dsl { ): Loader { @Suppress("UNCHECKED_CAST") val defaultEnv = Continuous2DEnvironment(incarnation as Incarnation) - val ctx = SimulationContext(incarnation, defaultEnv) + val ctx = SimulationContextImpl(incarnation, defaultEnv) @Suppress("UNCHECKED_CAST") context(ctx.environment, ctx.incarnation) { ctx.apply(block) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt index de4138a107..ed2d9ddb1b 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt @@ -12,7 +12,7 @@ package it.unibo.alchemist.boundary.dsl import it.unibo.alchemist.boundary.Exporter import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.OutputMonitor -import it.unibo.alchemist.boundary.dsl.model.SimulationContext +import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl import it.unibo.alchemist.boundary.exporters.GlobalExporter import it.unibo.alchemist.core.Engine import it.unibo.alchemist.core.Simulation @@ -25,7 +25,7 @@ import java.util.concurrent.Semaphore * * @param ctx The simulation context. */ -abstract class SingleUseDslLoader(private val ctx: SimulationContext<*, *>) : Loader { +abstract class SingleUseDslLoader(private val ctx: SimulationContextImpl<*, *>) : Loader { private val mutex = Semaphore(1) private var consumed = false diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/AvailableIncarnations.kt similarity index 95% rename from alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt rename to alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/AvailableIncarnations.kt index c8ab733905..43ffe0ce0c 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/Incarnation.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/AvailableIncarnations.kt @@ -12,7 +12,7 @@ package it.unibo.alchemist.boundary.dsl.model /** * Enumeration of available Alchemist incarnations. */ -enum class Incarnation { +enum class AvailableIncarnations { /** * SAPERE incarnation. */ diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt new file mode 100644 index 0000000000..5e2a7d0f43 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.PositionBasedFilter +import org.apache.commons.math3.random.RandomGenerator + +/** + * Context interface for managing node deployments in a simulation. + * + * Deployments define where nodes are placed in the environment and can be configured + * with content (molecules and concentrations), programs (reactions), and properties. + * + * ## Usage Example + * + * ```kotlin + * simulation(incarnation) { + * deployments { + * deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.25)) { + * all { + * molecule = "token" + * concentration = 1.0 + * } + * programs { + * all { + * program = "{token} --> {firing}" + * } + * } + * } + * } + * } + * ``` + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + * + * @see [SimulationContext.deployments] for configuring deployments in a simulation + * @see [Deployment] for the deployment interface + * @see [DeploymentContext] for configuring individual deployments + */ +@DslMarker +annotation class DeploymentsMarker + +/** + * Context interface for managing node deployments in a simulation. + * + * Deployments define where nodes are placed in the environment and can be configured + * with content (molecules and concentrations), programs (reactions), and properties. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + */ +@DeploymentsMarker +interface DeploymentsContext> { + /** + * The simulation context this deployments context belongs to. + */ + val ctx: SimulationContext + + /** + * The environment instance as a type-erased reference. + */ + val envAsAny: Environment<*, *> + + /** + * The environment instance where nodes are deployed. + * + * @see [Environment] + */ + val env: Environment + + /** + * The random number generator for scenario generation. + * + * Used for random deployments and position perturbations. + * + * @see [RandomGenerator] + */ + val generator: RandomGenerator + + /** + * Deploys nodes using a deployment with a configuration block. + * + * The configuration block allows setting content, programs, properties, and custom node factories. + * + * ```kotlin + * deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.25)) { + * all { molecule = "token" } + * } + * ``` + * + * @param deployment The deployment that defines node positions. + * @param block The configuration block for the deployment. + * @see [Deployment] + */ + fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) + + /** + * Deploys nodes using a deployment without additional configuration. + * + * Nodes are created at the positions defined by the deployment with default settings. + * + * @param deployment The deployment that defines node positions. + * @see [Deployment] + */ + fun deploy(deployment: Deployment<*>) +} + +/** + * Context interface for configuring a single deployment. + * + * This context allows configuring content (molecules and concentrations), programs (reactions), + * properties, and custom node factories for nodes deployed at positions defined by the deployment. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + * + * @see [DeploymentsContext] for the parent context + * @see [ContentContext] for configuring node content + * @see [ProgramsContext] for configuring node programs + * @see [PropertiesContext] for configuring node properties + */ +@DslMarker +annotation class DeploymentMarker + +/** + * Context interface for configuring a single deployment. + * + * This context allows configuring content (molecules and concentrations), programs (reactions), + * properties, and custom node factories for nodes deployed at positions defined by the deployment. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + */ +@DeploymentMarker +interface DeploymentContext> { + /** + * The deployments context this deployment context belongs to. + */ + val ctx: DeploymentsContext + + /** + * Configures content (molecules and concentrations) for all positions in the deployment. + * + * All nodes deployed at positions defined by this deployment will receive the configured content. + * + * ```kotlin + * all { + * molecule = "token" + * concentration = 1.0 + * } + * ``` + * + * @param block The content configuration block. + * @see [ContentContext] + */ + fun all(block: ContentContext.() -> Unit) + + /** + * Configures content for positions inside a filter. + * + * Only nodes deployed at positions matching the filter will receive the configured content. + * + * ```kotlin + * inside(RectangleFilter(-1.0, -1.0, 2.0, 2.0)) { + * molecule = "specialToken" + * } + * ``` + * + * @param filter The position filter to apply. + * @param block The content configuration block. + * @see [PositionBasedFilter] + * @see [ContentContext] + */ + fun inside(filter: PositionBasedFilter<*>, block: ContentContext.() -> Unit) + + /** + * Configures programs (reactions) for this deployment. + * + * Programs define the behavior of nodes through reactions. + * + * ```kotlin + * programs { + * all { + * program = "{token} --> {firing}" + * } + * } + * ``` + * + * @param block The programs configuration block. + * @see [ProgramsContext] + */ + fun programs(block: ProgramsContext.() -> Unit) + + /** + * Sets a custom node factory for this deployment. + * + * By default, nodes are created using the incarnation's node factory. + * This allows using custom node types. + * + * ```kotlin + * nodes { MyCustomNode() } + * ``` + * + * @param factory The factory function for creating nodes. + * @see [Node] + * @see [it.unibo.alchemist.model.Incarnation.createNode] + */ + fun nodes(factory: () -> Node) + + /** + * Configures properties for this deployment. + * + * Properties can be assigned to nodes based on their position. + * + * ```kotlin + * properties { + * inside(RectangleFilter(-3.0, -3.0, 2.0, 2.0)) { + * add(MyNodeProperty()) + * } + * } + * ``` + * + * @param block The properties configuration block. + * @see [PropertiesContext] + */ + fun properties(block: PropertiesContext.() -> Unit) +} + +/** + * Context interface for configuring node content (molecules and concentrations). + * + * This context is used within [DeploymentContext] blocks to define the initial + * content of nodes deployed at specific positions. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + * + * @see [DeploymentContext] for the parent context + * @see [it.unibo.alchemist.model.Incarnation.createMolecule] + * @see [it.unibo.alchemist.model.Incarnation.createConcentration] + */ +@DslMarker +annotation class ContentMarker + +/** + * Context interface for configuring node content (molecules and concentrations). + * + * This context is used within [DeploymentContext] blocks to define the initial + * content of nodes deployed at specific positions. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + */ +@ContentMarker +interface ContentContext> { + /** + * The optional position filter applied to this content context. + * + * If set, content is only applied to nodes at positions matching this filter. + */ + val filter: PositionBasedFilter

? + + /** + * The molecule name to inject into nodes. + * + * The molecule is created using the incarnation's molecule factory. + * + * @see [it.unibo.alchemist.model.Incarnation.createMolecule] + */ + var molecule: String? + + /** + * The concentration value for the molecule. + * + * The concentration is created using the incarnation's concentration factory. + * + * @see [it.unibo.alchemist.model.Incarnation.createConcentration] + */ + var concentration: T? +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt similarity index 70% rename from alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt rename to alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt index c2243ff8e5..40f29c2ed4 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt @@ -25,47 +25,37 @@ import it.unibo.alchemist.model.linkingrules.NoLinks * @param P The type of position. * @param ctx The simulation context. */ -open class DeploymentsContext>(val ctx: SimulationContext) { +open class DeploymentsContextImpl>(override val ctx: SimulationContext) : + DeploymentsContext { /** * The environment instance. */ - val environment: Environment<*, *> = ctx.environment as Environment<*, *> + override val envAsAny: Environment<*, *> = ctx.environment as Environment<*, *> /** * The environment instance. */ - val env = ctx.environment + override val env = ctx.environment /** * The scenario generator. */ - var generator = ctx.scenarioGenerator + override val generator = ctx.scenarioGenerator private val inc = ctx.incarnation - /** - * Deploys a deployment with a configuration block. - * - * @param deployment The deployment to configure. - * @param block The configuration block. - */ - fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) { + override fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) { logger.debug("Deploying deployment: {}", deployment) @Suppress("UNCHECKED_CAST") - val d = DeploymentContext(deployment as Deployment

).apply(block) + val d = DeploymentContextImpl(deployment as Deployment

).apply(block) // populate populateDeployment(d) } - /** - * Deploys a deployment without additional configuration. - * - * @param deployment The deployment to deploy. - */ - fun deploy(deployment: Deployment<*>) { + override fun deploy(deployment: Deployment<*>) { @Suppress("UNCHECKED_CAST") this.deploy(deployment) {} } - private fun populateDeployment(deploymentContext: DeploymentContext) { + private fun populateDeployment(deploymentContext: DeploymentContextImpl) { val deployment = deploymentContext.deployment // Additional linking rules deployment.getAssociatedLinkingRule()?.let { newLinkingRule -> @@ -113,11 +103,13 @@ open class DeploymentsContext>(val ctx: SimulationContext) { + inner class DeploymentContextImpl(val deployment: Deployment

) : DeploymentContext { + override val ctx: DeploymentsContext = this@DeploymentsContextImpl + /** * The list of content contexts for this deployment. */ - val contents: MutableList = mutableListOf() + val contents: MutableList = mutableListOf() /** * Optional factory for creating custom nodes. @@ -127,65 +119,39 @@ open class DeploymentsContext>(val ctx: SimulationContext = PropertiesContext(this@DeploymentsContext) + var propertiesContext: PropertiesContextImpl = PropertiesContextImpl(this@DeploymentContextImpl) /** * The programs context for this deployment. */ - val programsContext: ProgramsContext = ProgramsContext(this@DeploymentsContext) + val programsContext: ProgramsContextImpl = ProgramsContextImpl(this@DeploymentContextImpl) init { logger.debug("Visiting deployment: {}", deployment) } - /** - * Configures content for all positions in the deployment. - * - * @param block The content configuration block. - */ - fun all(block: ContentContext.() -> Unit) { + override fun all(block: ContentContext.() -> Unit) { logger.debug("Adding content for all positions") - val c = ContentContext().apply(block) + val c = ContentContextImpl().apply(block) contents.add(c) } - /** - * Configures content for positions inside a filter. - * - * @param filter The position filter. - * @param block The content configuration block. - */ - fun inside(filter: PositionBasedFilter<*>, block: ContentContext.() -> Unit) { + override fun inside(filter: PositionBasedFilter<*>, block: ContentContext.() -> Unit) { @Suppress("UNCHECKED_CAST") val typedFilter = filter as PositionBasedFilter

logger.debug("Adding content for positions inside filter: {}", typedFilter) - val c = ContentContext(typedFilter).apply(block) + val c = ContentContextImpl(typedFilter).apply(block) contents.add(c) } - /** - * Configures programs for this deployment. - * - * @param block The programs configuration block. - */ - fun programs(block: ProgramsContext.() -> Unit) { + override fun programs(block: ProgramsContext.() -> Unit) { programsContext.apply(block) } - /** - * Sets a custom node factory for this deployment. - * - * @param factory The factory function for creating nodes. - */ - fun nodes(factory: () -> Node) { + override fun nodes(factory: () -> Node) { nodeFactory = factory } - /** - * Configures properties for this deployment. - * - * @param block The properties configuration block. - */ - fun properties(block: PropertiesContext.() -> Unit) { + override fun properties(block: PropertiesContext.() -> Unit) { propertiesContext.apply(block) } @@ -196,7 +162,7 @@ open class DeploymentsContext>(val ctx: SimulationContext, position: P, content: ContentContext) { + fun applyToNodes(node: Node, position: P, content: ContentContextImpl) { logger.debug("Applying node to nodes for position: {}, deployment {}", position, deployment) if (content.filter == null || content.filter.contains(position)) { logger.debug("Creating molecule for node at position: {}", position) @@ -216,16 +182,16 @@ open class DeploymentsContext>(val ctx: SimulationContext? = null) { + inner class ContentContextImpl(override val filter: PositionBasedFilter

? = null) : ContentContext { /** * The molecule name. */ - var molecule: String? = null + override var molecule: String? = null /** * The concentration value. */ - var concentration: T? = null + override var concentration: T? = null } } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt index 2c3fdce8ae..0243cd07d4 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt @@ -14,28 +14,63 @@ import it.unibo.alchemist.boundary.Extractor import it.unibo.alchemist.model.Position /** - * Context for configuring exporters in a simulation. + * Context interface for configuring data exporters in a simulation. + * + * Exporters define how simulation data is extracted and exported, supporting formats + * such as CSV, MongoDB, and custom formats. + * Data can be exported per-node or aggregated + * using statistical functions. + * + * ## Usage Example + * + * ```kotlin +* exporter { +* type = CSVExporter("output", 4.0) +* data(Time(), moleculeReader("moleculeName")) +* } + * ``` * * @param T The type of molecule concentration. - * @param P The type of position. + * @param P The type of position, must extend [Position]. + * + * @see [SimulationContext.exporter] for adding exporters to a simulation + * @see [Exporter] for the exporter interface + * @see [Extractor] for data extraction */ -class ExporterContext> { - /** - * The exporter type. - */ - var type: Exporter? = null +@DslMarker +annotation class ExporterMarker +/** + * Context interface for configuring data exporters in a simulation. + * + * Exporters define how simulation data is extracted and exported, supporting formats + * such as CSV, MongoDB, and custom formats. + * Data can be exported per-node or aggregated + * using statistical functions. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + */ +@ExporterMarker +interface ExporterContext> { /** - * The list of data extractors. + * The exporter instance that handles data output. + * + * @see [Exporter] */ - var extractors: List> = emptyList() + var type: Exporter? /** * Sets the data extractors for this exporter. * - * @param extractors The extractors to use. + * Extractors define which data should be exported from the simulation. + * + * ```kotlin + * data(Time(), moleculeReader("moleculeName")) + * ``` + * + * @param extractors The extractors to use for data extraction. + * @see [Extractor] */ - fun data(vararg extractors: Extractor<*>) { - this.extractors = extractors.toList() - } + fun data(vararg extractors: Extractor<*>) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt new file mode 100644 index 0000000000..685ec6eb35 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.Exporter +import it.unibo.alchemist.boundary.Extractor +import it.unibo.alchemist.model.Position + +/** + * Context for configuring exporters in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +class ExporterContextImpl> : ExporterContext { + override var type: Exporter? = null + + /** + * The list of data extractors. + */ + var extractors: List> = emptyList() + + override fun data(vararg extractors: Extractor<*>) { + this.extractors = extractors.toList() + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt index e45bf2aa04..3e8f7ec20b 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt @@ -13,19 +13,50 @@ import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.Position /** - * Context for configuring layers in a simulation. + * Context interface for configuring spatial layers in a simulation. + * + * Layers define overlays of data that can be sensed everywhere in the environment. + * They can be used to model physical properties such as pollution, light, temperature, etc. + * + * ## Usage Example + * + * ```kotlin +* layer { +* molecule = "A" +* layer = StepLayer(2.0, 2.0, 100.0, 0.0) +* } + * ``` + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + * + * @see [SimulationContext.layer] for adding layers to a simulation + * @see [Layer] for the layer interface + */ +@DslMarker +annotation class LayerMarker + +/** + * Context interface for configuring spatial layers in a simulation. + * + * Layers define overlays of data that can be sensed everywhere in the environment. + * They can be used to model physical properties such as pollution, light, temperature, etc. * * @param T The type of molecule concentration. - * @param P The type of position. + * @param P The type of position, must extend [Position]. */ -class LayerContext> { +@LayerMarker +interface LayerContext> { /** - * The molecule name for the layer. + * The molecule name associated with this layer. + * */ - var molecule: String? = null + var molecule: String? /** - * The layer instance. + * The layer instance that provides spatial data. + * + * @see [Layer] */ - var layer: Layer? = null + var layer: Layer? } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContextImpl.kt new file mode 100644 index 0000000000..89d546c573 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContextImpl.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.model.Layer +import it.unibo.alchemist.model.Position + +/** + * Context for configuring layers in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +class LayerContextImpl> : LayerContext { + override var molecule: String? = null + + override var layer: Layer? = null +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt index fd369345d6..9dea1409f2 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt @@ -1,6 +1,14 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Condition import it.unibo.alchemist.model.Node @@ -10,163 +18,179 @@ import it.unibo.alchemist.model.Reaction import it.unibo.alchemist.model.TimeDistribution /** - * Context for managing programs (reactions) in a simulation. + * Context interface for configuring programs (reactions) in a deployment. + * + * Programs define the behavior of nodes through reactions that execute actions + * when conditions are met. Programs can be applied to all nodes or filtered by position. + * + * ## Usage Example + * + * ```kotlin + * deployments { + * deploy(deployment) { + * programs { + * all { + * timeDistribution("1") + * program = "{token} --> {firing}" + * } + * inside(RectangleFilter(-1.0, -1.0, 2.0, 2.0)) { + * program = "{firing} --> +{token}" + * } + * } + * } + * } + * ``` * * @param T The type of molecule concentration. - * @param P The type of position. - * @param ctx The deployments context. + * @param P The type of position, must extend [Position]. + * + * @see [DeploymentContext.programs] for configuring programs in a deployment + * @see [Reaction] for the reaction interface + * @see [TimeDistribution] for time distribution configuration */ -class ProgramsContext>(val ctx: DeploymentsContext) { +@DslMarker +annotation class ProgramsMarker + +/** + * Context interface for configuring programs (reactions) in a deployment. + * + * Programs define the behavior of nodes through reactions that execute actions + * when conditions are met. Programs can be applied to all nodes or filtered by position. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + */ +@ProgramsMarker +interface ProgramsContext> { /** - * Entry representing a program with its filter. - * - * @param filter Optional position filter. - * @param program The program configuration block. + * The deployment context this programs context belongs to. */ - inner class ProgramEntry( - val filter: PositionBasedFilter

?, - val program: ProgramsContext.ProgramContext.() -> Unit, - ) + val ctx: DeploymentContext /** - * List of program entries. + * Configures a program for all nodes in the deployment. + * + * @param block The program configuration block. */ - val programs: MutableList = mutableListOf() + fun all(block: ProgramContext.() -> Unit) /** - * Configures a program for all nodes. + * Configures a program for nodes inside a position filter. + * + * Only nodes whose positions match the filter will receive the configured program. * + * @param filter The position filter to apply. * @param block The program configuration block. + * @see [PositionBasedFilter] */ - fun all(block: ProgramContext.() -> Unit) { - logger.debug("Adding program for all nodes") - programs.add(ProgramEntry(null, block)) - } + fun inside(filter: PositionBasedFilter

, block: ProgramContext.() -> Unit) +} +/** + * Context interface for configuring a single program (reaction) for a node. + * + * This context is used within [ProgramsContext] blocks to define reactions with + * their time distributions, conditions, and actions. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + * + * @see [ProgramsContext] for the parent context + * @see [Reaction] for the reaction interface + * @see [TimeDistribution] for time distribution + * @see [Action] for reaction actions + * @see [Condition] for reaction conditions + */ +@DslMarker +annotation class ProgramMarker + +/** + * Context interface for configuring a single program (reaction) for a node. + * + * This context is used within [ProgramsContext] blocks to define reactions with + * their time distributions, conditions, and actions. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + */ +@ProgramMarker +interface ProgramContext> { /** - * Configures a program for nodes inside a filter. + * The programs context this program context belongs to. + */ + val ctx: ProgramsContext + + /** + * The node this program context is configuring. + */ + val node: Node + + /** + * The program specification as a string. * - * @param filter The position filter. - * @param block The program configuration block. + * The format depends on the incarnation being used. */ - fun inside(filter: PositionBasedFilter

, block: ProgramContext.() -> Unit) { - logger.debug("Adding program for nodes inside filter: {}", filter) - programs.add(ProgramEntry(filter, block)) - } + var program: String? /** - * Applies a program to nodes at a specific position. + * The time distribution for the reaction. * - * @param node The node to apply the program to. - * @param position The position of the node. - * @param program The program configuration block. - * @param filter Optional position filter. + * @see [TimeDistribution] */ - fun applyToNodes(node: Node, position: P, program: ProgramContext.() -> Unit, filter: PositionBasedFilter

?) { - logger.debug("Applying program to node at position: {}", position) - val c = ProgramContext(node, this).apply(program) - if (filter != null && !filter.contains(position)) { - return - } - logger.debug("Creating time distribution for program") - val timeDistribution = c.timeDistribution - ?: ctx.ctx.incarnation.createTimeDistribution( - ctx.ctx.simulationGenerator, - ctx.ctx.environment, - node, - null, - ) - logger.debug("Creating reaction for program") - val r = c.reaction ?: run { - // Create a basic reaction with custom actions/conditions - ctx.ctx.incarnation.createReaction( - ctx.ctx.simulationGenerator, - ctx.ctx.environment, - node, - timeDistribution, - c.program, - ) - } - logger.debug("Adding actions to reaction") - r.actions += c.actions.map { it() } - logger.debug("Adding conditions to reaction") - r.conditions += c.conditions.map { it() } - - logger.debug("Adding condition to reaction") - node.addReaction(r) - } + var timeDistribution: TimeDistribution? /** - * Context for configuring a single program (reaction). + * An optional custom reaction instance. + * + * If provided, this reaction will be used instead of creating one from [program]. + * + * @see [Reaction] + */ + var reaction: Reaction? + + /** + * Sets the time distribution using a string specification. + * + * The string is processed by the incarnation to create a [TimeDistribution]. + * + * ```kotlin + * timeDistribution("1") + * ``` + * + * @param td The time distribution specification string. + * @see [TimeDistribution] + * @see [it.unibo.alchemist.model.Incarnation.createTimeDistribution] + */ + fun timeDistribution(td: String) + + /** + * Adds an action to the program. + * + * Actions are executed when the reaction fires and all conditions are met. + * + * @param block A factory function that creates the action. + * @see [Action] + */ + fun addAction(block: () -> Action) + + /** + * Adds a condition to the program. + * + * Conditions must all be satisfied for the reaction to fire. + * + * @param block A factory function that creates the condition. + * @see [Condition] + */ + fun addCondition(block: () -> Condition) + + /** + * Unary plus operator for type-safe casting of [TimeDistribution]. + * + * This operator allows casting a [TimeDistribution] with wildcard type parameter + * to a specific type parameter, enabling type-safe usage in generic contexts. * - * @param node The node this program is associated with. - * @param ctx The programs context. + * @return The same [TimeDistribution] instance cast to the specified type parameter. */ - open inner class ProgramContext(val node: Node, val ctx: ProgramsContext) { - /** - * The program name. - */ - var program: String? = null - - /** - * Collection of action factories. - */ - var actions: Collection<() -> Action> = emptyList() - - /** - * Collection of condition factories. - */ - var conditions: Collection<() -> Condition> = emptyList() - - /** - * The time distribution for the reaction. - */ - var timeDistribution: TimeDistribution? = null - - /** - * Optional custom reaction instance. - */ - var reaction: Reaction? = null - - /** - * Sets the time distribution using a string specification. - * - * @param td The time distribution specification. - */ - fun timeDistribution(td: String) { - timeDistribution = ctx.ctx.ctx.incarnation.createTimeDistribution( - ctx.ctx.ctx.simulationGenerator, - ctx.ctx.ctx.environment, - node, - td, - ) - } - - /** - * Adds an action to the program. - * - * @param block The action factory. - */ - fun addAction(block: () -> Action) { - actions += block - } - - /** - * Adds a condition to the program. - * - * @param block The condition factory. - */ - fun addCondition(block: () -> Condition) { - conditions += block - } - - /** - * Unary plus operator for type casting time distributions. - * - * @param T The target type. - * @return The cast time distribution. - */ - @Suppress("UNCHECKED_CAST") - operator fun TimeDistribution<*>.unaryPlus(): TimeDistribution = this as TimeDistribution - } + @Suppress("UNCHECKED_CAST") + operator fun TimeDistribution<*>.unaryPlus(): TimeDistribution = this as TimeDistribution } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt new file mode 100644 index 0000000000..d28b8b9562 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt @@ -0,0 +1,147 @@ +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger +import it.unibo.alchemist.model.Action +import it.unibo.alchemist.model.Condition +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.PositionBasedFilter +import it.unibo.alchemist.model.Reaction +import it.unibo.alchemist.model.TimeDistribution + +/** + * Context for managing programs (reactions) in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + * @param ctx The deployments context. + */ +class ProgramsContextImpl>(override val ctx: DeploymentContext) : ProgramsContext { + /** + * Entry representing a program with its filter. + * + * @param filter Optional position filter. + * @param program The program configuration block. + */ + inner class ProgramEntry( + val filter: PositionBasedFilter

?, + val program: ProgramsContextImpl.ProgramContextImpl.() -> Unit, + ) + + /** + * List of program entries. + */ + val programs: MutableList = mutableListOf() + + override fun all(block: ProgramContext.() -> Unit) { + logger.debug("Adding program for all nodes") + programs.add(ProgramEntry(null, block)) + } + + override fun inside(filter: PositionBasedFilter

, block: ProgramContext.() -> Unit) { + logger.debug("Adding program for nodes inside filter: {}", filter) + programs.add(ProgramEntry(filter, block)) + } + + /** + * Applies a program to nodes at a specific position. + * + * @param node The node to apply the program to. + * @param position The position of the node. + * @param program The program configuration block. + * @param filter Optional position filter. + */ + fun applyToNodes( + node: Node, + position: P, + program: ProgramContextImpl.() -> Unit, + filter: PositionBasedFilter

?, + ) { + logger.debug("Applying program to node at position: {}", position) + val c = ProgramContextImpl(node).apply(program) + val context = ctx.ctx.ctx + if (filter != null && !filter.contains(position)) { + return + } + logger.debug("Creating time distribution for program") + val timeDistribution = c.timeDistribution + ?: context.incarnation.createTimeDistribution( + context.simulationGenerator, + context.environment, + node, + null, + ) + logger.debug("Creating reaction for program") + val r = c.reaction ?: run { + // Create a basic reaction with custom actions/conditions + context.incarnation.createReaction( + context.simulationGenerator, + context.environment, + node, + timeDistribution, + c.program, + ) + } + logger.debug("Adding actions to reaction") + r.actions += c.actions.map { it() } + logger.debug("Adding conditions to reaction") + r.conditions += c.conditions.map { it() } + + logger.debug("Adding condition to reaction") + node.addReaction(r) + } + + /** + * Context for configuring a single program (reaction). + * + * @param node The node this program is associated with. + * @param ctx The programs context. + */ + open inner class ProgramContextImpl(override val node: Node) : ProgramContext { + + override val ctx: ProgramsContext = this@ProgramsContextImpl + + /** + * The program name. + */ + override var program: String? = null + + /** + * Collection of action factories. + */ + var actions: Collection<() -> Action> = emptyList() + + /** + * Collection of condition factories. + */ + var conditions: Collection<() -> Condition> = emptyList() + + /** + * The time distribution for the reaction. + */ + override var timeDistribution: TimeDistribution? = null + + /** + * Optional custom reaction instance. + */ + override var reaction: Reaction? = null + + override fun timeDistribution(td: String) { + val c = ctx.ctx.ctx.ctx + timeDistribution = c.incarnation.createTimeDistribution( + c.simulationGenerator, + c.environment, + node, + td, + ) + } + + override fun addAction(block: () -> Action) { + actions += block + } + + override fun addCondition(block: () -> Condition) { + conditions += block + } + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt index 220ad12d30..b124401c04 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt @@ -1,90 +1,131 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.NodeProperty import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter /** - * Context for managing node properties in a simulation. + * Context interface for configuring node properties in a deployment. + * + * Properties can be assigned to nodes based on their position using filters, + * or applied to all nodes in the deployment. + * + * ## Usage Example + * + * ```kotlin + * deployments { + * deploy(deployment) { + * properties { + * inside(RectangleFilter(-3.0, -3.0, 2.0, 2.0)) { + * add(MyNodeProperty()) + * } + * all { + * add(CommonProperty()) + * } + * } + * } + * } + * ``` + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + * + * @see [DeploymentContext.properties] for configuring properties in a deployment + * @see [NodeProperty] for the property interface + * @see [PositionBasedFilter] for position filtering + */ +@DslMarker +annotation class PropertiesMarker + +/** + * Context interface for configuring node properties in a deployment. + * + * Properties can be assigned to nodes based on their position using filters, + * or applied to all nodes in the deployment. * * @param T The type of molecule concentration. - * @param P The type of position. + * @param P The type of position, must extend [Position]. */ -class PropertiesContext>(val ctx: DeploymentsContext) { +@PropertiesMarker +interface PropertiesContext> { /** - * List of property contexts with their associated filters. + * The deployment context this properties context belongs to. */ - val propertiesCtx: MutableList Unit, PositionBasedFilter

?>> = mutableListOf() + val ctx: DeploymentContext /** * Configures properties for nodes inside a position filter. * - * @param filter The position filter. + * Only nodes whose positions match the filter will receive the configured properties. + * + * @param filter The position filter to apply. * @param block The property configuration block. + * @see [PositionBasedFilter] */ - fun inside(filter: PositionBasedFilter<*>, block: PropertyContext.() -> Unit) { - @Suppress("UNCHECKED_CAST") - val typedFilter = filter as PositionBasedFilter

- propertiesCtx.add(block to typedFilter) - logger.debug("Adding property for nodes inside filter: {}", typedFilter) - } + fun inside(filter: PositionBasedFilter<*>, block: PropertyContext.() -> Unit) /** - * Configures properties for all nodes. + * Configures properties for all nodes in the deployment. * * @param block The property configuration block. */ - fun all(block: PropertyContext.() -> Unit) { - propertiesCtx.add(block to null) - logger.debug("Adding property for all nodes") - } + fun all(block: PropertyContext.() -> Unit) +} +/** + * Context interface for configuring properties for a specific node. + * + * This context is used within [PropertiesContext] blocks to add properties to nodes. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + * + * @see [PropertiesContext] for the parent context + * @see [NodeProperty] for the property interface + */ +@DslMarker +annotation class PropertyMarker + +/** + * Context interface for configuring properties for a specific node. + * + * This context is used within [PropertiesContext] blocks to add properties to nodes. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [Position]. + */ +@PropertyMarker +interface PropertyContext> { /** - * Applies configured properties to a node at a specific position. - * - * @param node The node to apply properties to. - * @param position The position of the node. + * The properties context this property context belongs to. */ - fun applyToNode(node: Node, position: P) { - propertiesCtx.forEach { (propertyCtx, filter) -> - if (filter == null || filter.contains(position)) { - val properties = PropertyContext(filter, node, this) - .apply(propertyCtx) - .properties - properties.forEach { property -> - logger.debug("Applying property: {} to node: {}", property, node) - node.addProperty(property) - } - } - } - } + val ctx: PropertiesContext /** - * Context for configuring properties for a specific node. - * - * @param filter Optional position filter. - * @param node The node to configure properties for. + * The optional position filter applied to this property context. + */ + val filter: PositionBasedFilter

? + + /** + * The node this property context is configuring. */ - inner class PropertyContext( - val filter: PositionBasedFilter

?, - val node: Node, - val ctx: PropertiesContext, - ) { - /** - * List of properties to add to the node. - */ - val properties: MutableList> = mutableListOf() + val node: Node - /** - * Adds a property to the node. - * - * @param property The property to add. - */ - fun add(property: NodeProperty) { - logger.debug("Adding property: {}", property) - properties.add(property) - } - } + /** + * Adds a property to the node. + * + * @param property The property to add to the node. + * @see [NodeProperty] + */ + fun add(property: NodeProperty) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt new file mode 100644 index 0000000000..c9f7b6638b --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt @@ -0,0 +1,73 @@ +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.NodeProperty +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.PositionBasedFilter + +/** + * Context for managing node properties in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +class PropertiesContextImpl>(override val ctx: DeploymentContext) : PropertiesContext { + /** + * List of property contexts with their associated filters. + */ + val propertiesCtx: MutableList Unit, PositionBasedFilter

?>> = mutableListOf() + + override fun inside(filter: PositionBasedFilter<*>, block: PropertyContext.() -> Unit) { + @Suppress("UNCHECKED_CAST") + val typedFilter = filter as PositionBasedFilter

+ propertiesCtx.add(block to typedFilter) + logger.debug("Adding property for nodes inside filter: {}", typedFilter) + } + + override fun all(block: PropertyContext.() -> Unit) { + propertiesCtx.add(block to null) + logger.debug("Adding property for all nodes") + } + + /** + * Applies configured properties to a node at a specific position. + * + * @param node The node to apply properties to. + * @param position The position of the node. + */ + fun applyToNode(node: Node, position: P) { + propertiesCtx.forEach { (propertyCtx, filter) -> + if (filter == null || filter.contains(position)) { + val properties = PropertyContextImpl(filter, node) + .apply(propertyCtx) + .properties + properties.forEach { property -> + logger.debug("Applying property: {} to node: {}", property, node) + node.addProperty(property) + } + } + } + } + + /** + * Context for configuring properties for a specific node. + * + * @param filter Optional position filter. + * @param node The node to configure properties for. + */ + inner class PropertyContextImpl(override val filter: PositionBasedFilter

?, override val node: Node) : + PropertyContext { + override val ctx: PropertiesContext = this@PropertiesContextImpl + + /** + * List of properties to add to the node. + */ + val properties: MutableList> = mutableListOf() + + override fun add(property: NodeProperty) { + logger.debug("Adding property: {}", property) + properties.add(property) + } + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index e6a03afcc6..d63184107e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -7,182 +7,224 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -@file:Suppress("UNCHECKED_CAST") - package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger -import it.unibo.alchemist.boundary.launchers.DefaultLauncher +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GlobalReaction import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.TerminationPredicate -import it.unibo.alchemist.model.linkingrules.NoLinks import java.io.Serializable -import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator /** - * Main context for building and configuring a simulation. + * Main context interface for building and configuring Alchemist simulations using the DSL. + * + * This interface provides a type-safe way to configure simulations programmatically. + * It serves as the entry point for DSL users to define + * all aspects of a simulation including deployments, programs, monitors, exporters, and more. + * + * ## Usage Example + * + * ```kotlin + * simulation(incarnation, environment) { + * networkModel = ConnectWithinDistance(0.5) + * deployments { + * deploy(Grid(-5, -5, 5, 5, 0.25, 0.25)) { + * all { + * molecule = "moleculeName" + * concentration = 1.0 + * } + * } + * } + * } + * ``` + * + * @param T The type of molecule concentration used in the simulation + * @param P The type of position used in the environment, must extend [Position] * - * @param T The type of molecule concentration. - * @param P The type of position. - * @param incarnation The incarnation instance. - * @param environment The environment instance. + * @see [it.unibo.alchemist.boundary.dsl.Dsl] for creating simulation contexts + * @see [DeploymentsContextImpl] for deployment configuration + * @see [ProgramsContextImpl] for program configuration + * @see [ExporterContextImpl] for exporter configuration + * @see [LayerContextImpl] for layer configuration */ -class SimulationContext>(val incarnation: Incarnation, val environment: Environment) { - /** - * List of build steps to execute. - */ - val buildSteps: MutableList<() -> Unit> = mutableListOf() +@DslMarker +annotation class SimulationMarker +/** + * Main context interface for building and configuring Alchemist simulations using the DSL. + * + * This interface provides a type-safe way to configure simulations programmatically. + * It serves as the entry point for DSL users to define + * all aspects of a simulation including deployments, programs, monitors, exporters, and more. + * + * @param T The type of molecule concentration used in the simulation + * @param P The type of position used in the environment, must extend [Position] + */ +@SimulationMarker +interface SimulationContext> { /** - * List of output monitors. + * The incarnation instance that defines how molecules, nodes, and reactions are created. + * + * ## Creating an Incarnation + * + * Incarnations are created from the [AvailableIncarnations] enum using the extension function: + * ```kotlin + * + * simulation(AvailableIncarnations.SAPERE.incarnation(), environment) { + * // simulation configuration + * } + * ``` + * + * + * @see [AvailableIncarnations] for the DSL enum of available incarnations + * @see [Incarnation] for the incarnation interface + * @see [it.unibo.alchemist.boundary.dsl.Dsl.incarnation] for converting enum to instance */ - val monitors: MutableList> = mutableListOf() + val incarnation: Incarnation /** - * List of exporters. + * The environment where the simulation takes place. + * + * @see [Environment] */ - val exporters: MutableList> = mutableListOf() + val environment: Environment /** - * The launcher for the simulation. + * The launcher responsible for executing the simulation. + * + * Some implementations are available in [it.unibo.alchemist.boundary.launchers]. + * + * @see [Launcher] */ - var launcher: Launcher = DefaultLauncher() + var launcher: Launcher /** - * The random generator for scenario generation. + * Random number generator controlling the evolution of the events of the simulation. + * + * @see [RandomGenerator] */ - var scenarioGenerator: RandomGenerator = MersenneTwister(0L) + var simulationGenerator: RandomGenerator /** - * The random generator for simulation execution. + * Random number generator controlling the position of random deployments. + * + * @see [RandomGenerator] */ - var simulationGenerator: RandomGenerator = MersenneTwister(0L) - - private val layers: MutableMap> = HashMap() - private var _networkModel: LinkingRule = NoLinks() + var scenarioGenerator: RandomGenerator /** - * The network model (linking rule) for the environment. + * The network model (linking rule) that defines how nodes connect in the environment. + * + * @see [LinkingRule] */ var networkModel: LinkingRule - get() = _networkModel - set(value) { - _networkModel = value - environment.linkingRule = value - } /** - * The variables context for managing simulation variables. - */ - val variablesContext = VariablesContext() - - /** - * Executes all build steps. - */ - fun build() { - buildSteps.forEach { it() } - } - - /** - * Configures deployments for the simulation. + * Configures node deployments for the simulation. * - * @param block The deployments configuration block. + * ## Usage Example + * ```kotlin + * deployments { + * deploy(point(0,0)) + * ... + * } + * ``` + * + * @see [DeploymentsContextImpl] to configure deployments */ - fun deployments(block: DeploymentsContext.() -> Unit) { - buildSteps.add { DeploymentsContext(this).apply(block) } - } + fun deployments(block: DeploymentsContextImpl.() -> Unit) /** * Adds a termination predicate to the simulation. * - * @param predicate The termination predicate. + * @param terminator The termination predicate to add + * @see [TerminationPredicate] */ - fun addTerminator(predicate: TerminationPredicate<*, *>) { - @Suppress("UNCHECKED_CAST") - buildSteps.add { environment.addTerminator(predicate as TerminationPredicate) } - } + fun addTerminator(terminator: TerminationPredicate<*, *>) /** * Adds an output monitor to the simulation. * - * @param monitor The output monitor. + * @param monitor The output monitor to add + * @see [OutputMonitor] */ - fun addMonitor(monitor: OutputMonitor) { - buildSteps.add { monitors.add(monitor) } - } + fun addMonitor(monitor: OutputMonitor) /** - * Configures an exporter for the simulation. + * Add an exporter to the simulation for data output. * - * @param block The exporter configuration block. + * @param block The configuration block + * @see [ExporterContextImpl] */ - fun exporter(block: ExporterContext.() -> Unit) { - buildSteps.add { exporters.add(ExporterContext().apply(block)) } - } + fun exporter(block: ExporterContextImpl.() -> Unit) /** - * Adds a global reaction to the simulation. + * Configures a global program. * - * @param program The global reaction. + * @param program the global reaction to add + * @see [GlobalReaction] */ - fun program(program: GlobalReaction) { - buildSteps.add { this.environment.addGlobalReaction(program) } - } + fun program(program: GlobalReaction) /** - * Schedules a block to run later during build. + * Schedules a block of code to execute later during the loading process. + * + * This is useful for debug purposes or for operations that need to be deferred * - * @param block The block to execute. + * Example: + * ```kotlin + * runLater { + * environment.nodes.forEach { node -> + * println("Node: ${node}") + * } + * } + * ``` + * + * @param block The block of code to execute later */ - fun runLater(block: () -> Unit) { - buildSteps.add { block() } - } + fun runLater(block: () -> Unit) /** - * Configures a layer for the simulation. + * Add a spatial layer for a molecule. + * + * It is possible to define overlays (layers) of data that can be sensed + * everywhere in the environment * - * @param block The layer configuration block. + * @param block The configuration block + * @see [LayerContextImpl] */ - fun layer(block: LayerContext.() -> Unit) { - buildSteps.add { - val l = LayerContext().apply(block) - val layer = requireNotNull(l.layer) { "Layer must be specified" } - val moleculeName = requireNotNull(l.molecule) { "Molecule must be specified" } - require(!this.layers.containsKey(moleculeName)) { - "Inconsistent layer definition for molecule $moleculeName. " + - "There must be a single layer per molecule" - } - val molecule = incarnation.createMolecule(moleculeName) - logger.debug("Adding layer for molecule {}: {}", moleculeName, layer) - layers[moleculeName] = layer - environment.addLayer(molecule, layer) - } - } + fun layer(block: LayerContextImpl.() -> Unit) /** - * Registers a variable in the variables context. + * Registers a Linear Variable for batch simulations. * - * @param source The variable source. - * @return A variable provider for property delegation. + * Example usage with a range variable: + * ```kotlin + * var myParam by variable(RangeVariable(0.0, 10.0, 0.5)) + * ``` + * + * @param source The variable source that provides the range of values + * @see [Variable] */ - fun variable(source: Variable): VariablesContext.VariableProvider = - variablesContext.register(source) + fun variable(source: Variable): VariablesContext.VariableProvider /** - * Registers a dependent variable in the variables context. + * Registers a dependent variable that is computed from other variables. + * + * Example usage:: + * ```kotlin + * var param by variable(RangeVariable(0.0, 10.0, 0.5)) + * var computedParam by variable { param * 2.0 } + * ``` * - * @param source The function that provides the variable value. - * @return A dependent variable provider for property delegation. + * @param source A function that computes the variable value */ - fun variable(source: () -> T): VariablesContext.DependentVariableProvider = - variablesContext.dependent(source) + fun variable(source: () -> T): VariablesContext.DependentVariableProvider } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt new file mode 100644 index 0000000000..fec3a01c4e --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +@file:Suppress("UNCHECKED_CAST") + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.Launcher +import it.unibo.alchemist.boundary.OutputMonitor +import it.unibo.alchemist.boundary.Variable +import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger +import it.unibo.alchemist.boundary.launchers.DefaultLauncher +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.GlobalReaction +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Layer +import it.unibo.alchemist.model.LinkingRule +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.TerminationPredicate +import it.unibo.alchemist.model.linkingrules.NoLinks +import java.io.Serializable +import org.apache.commons.math3.random.MersenneTwister +import org.apache.commons.math3.random.RandomGenerator + +/** + * Main context for building and configuring a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ + +class SimulationContextImpl>( + override val incarnation: Incarnation, + override val environment: Environment, +) : SimulationContext { + /** + * List of build steps to execute. + */ + val buildSteps: MutableList<() -> Unit> = mutableListOf() + + /** + * List of output . + */ + val monitors: MutableList> = mutableListOf() + + /** + * List of exporters. + */ + val exporters: MutableList> = mutableListOf() + + override var launcher: Launcher = DefaultLauncher() + + override var scenarioGenerator: RandomGenerator = MersenneTwister(0L) + + override var simulationGenerator: RandomGenerator = MersenneTwister(0L) + + private val layers: MutableMap> = HashMap() + private var _networkModel: LinkingRule = NoLinks() + + override var networkModel: LinkingRule + get() = _networkModel + set(value) { + _networkModel = value + environment.linkingRule = value + } + + /** + * The variables context for managing simulation variables. + */ + val variablesContext = VariablesContext() + + /** + * Executes all build steps. + */ + fun build() { + buildSteps.forEach { it() } + } + + override fun deployments(block: DeploymentsContextImpl.() -> Unit) { + buildSteps.add { DeploymentsContextImpl(this).apply(block) } + } + + override fun addTerminator(terminator: TerminationPredicate<*, *>) { + @Suppress("UNCHECKED_CAST") + buildSteps.add { environment.addTerminator(terminator as TerminationPredicate) } + } + + override fun addMonitor(monitor: OutputMonitor) { + buildSteps.add { monitors.add(monitor) } + } + + override fun exporter(block: ExporterContextImpl.() -> Unit) { + buildSteps.add { exporters.add(ExporterContextImpl().apply(block)) } + } + + override fun program(program: GlobalReaction) { + buildSteps.add { this.environment.addGlobalReaction(program) } + } + + override fun runLater(block: () -> Unit) { + buildSteps.add { block() } + } + + override fun layer(block: LayerContextImpl.() -> Unit) { + buildSteps.add { + val l = LayerContextImpl().apply(block) + val layer = requireNotNull(l.layer) { "Layer must be specified" } + val moleculeName = requireNotNull(l.molecule) { "Molecule must be specified" } + require(!this.layers.containsKey(moleculeName)) { + "Inconsistent layer definition for molecule $moleculeName. " + + "There must be a single layer per molecule" + } + val molecule = incarnation.createMolecule(moleculeName) + logger.debug("Adding layer for molecule {}: {}", moleculeName, layer) + layers[moleculeName] = layer + environment.addLayer(molecule, layer) + } + } + + override fun variable(source: Variable): VariablesContext.VariableProvider = + variablesContext.register(source) + + override fun variable(source: () -> T): VariablesContext.DependentVariableProvider = + variablesContext.dependent(source) +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt index 037e11e12c..1e29057b7e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt @@ -9,9 +9,6 @@ package it.unibo.alchemist.boundary.dsl.scripting -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken -import java.io.File import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.api.compilerOptions @@ -33,54 +30,53 @@ interface AlchemistScript * Compilation configuration for Alchemist scripts. */ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ - defaultImports(*loadDefaultImports().toTypedArray()) - - jvm { - dependenciesFromClassContext(AlchemistScript::class, wholeClasspath = true) - compilerOptions.append("-Xcontext-parameters") - } -}) { - @Suppress("UnusedPrivateMember") - private fun readResolve(): Any = AlchemistCompilationConfiguration -} - -private fun loadDefaultImports(): List { - val defaultImports = listOf( + defaultImports( "it.unibo.alchemist.boundary.dsl.Dsl.simulation", + "it.unibo.alchemist.boundary.dsl.Dsl.incarnation", + "it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.*", "it.unibo.alchemist.boundary.dsl.model.Incarnation.*", "it.unibo.alchemist.boundary.dsl.generated.*", "it.unibo.alchemist.boundary.dsl.*", + "it.unibo.alchemist.model.maps.actions.*", + "it.unibo.alchemist.model.maps.deployments.*", + "it.unibo.alchemist.model.maps.environments.*", "it.unibo.alchemist.model.*", + "it.unibo.alchemist.model.positions.*", + "it.unibo.alchemist.model.deployments.*", + "it.unibo.alchemist.model.positionfilters.And", + "it.unibo.alchemist.model.positionfilters.Or", + "it.unibo.alchemist.model.positionfilters.Not", + "it.unibo.alchemist.model.positionfilters.Xor", + "it.unibo.alchemist.model.actions.*", + "it.unibo.alchemist.model.conditions.*", + "it.unibo.alchemist.model.environments.*", + "it.unibo.alchemist.model.geometry.*", + "it.unibo.alchemist.model.layers.*", + "it.unibo.alchemist.model.linkingrules.*", + "it.unibo.alchemist.model.movestrategies.*", + "it.unibo.alchemist.model.neighborhoods.*", + "it.unibo.alchemist.model.nodes.*", + "it.unibo.alchemist.model.properties.*", + "it.unibo.alchemist.model.routes.*", + "it.unibo.alchemist.model.reactions.*", + "it.unibo.alchemist.model.terminators.*", + "it.unibo.alchemist.model.timedistributions.*", + "it.unibo.alchemist.boundary.properties.*", + "it.unibo.alchemist.boundary.dsl.aliases.*", + "it.unibo.alchemist.boundary.exporters.*", + "it.unibo.alchemist.boundary.extractors.*", + "it.unibo.alchemist.boundary.launchers.*", + "it.unibo.alchemist.boundary.statistic.*", + "it.unibo.alchemist.boundary.exportfilters.*", + "it.unibo.alchemist.boundary.variables.*", + "it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger", ) - val configFileName = "alchemist-default-imports.json" - val type = object : TypeToken>() {}.type - val mergedImports = defaultImports.toMutableList() - val seenImports = defaultImports.toMutableSet() - - fun loadAndMergeImports(json: String) { - try { - val loadedImports = Gson().fromJson>(json, type) ?: return - loadedImports.forEach { import -> - if (seenImports.add(import)) { - mergedImports.add(import) - } - } - } catch (e: Exception) { - } - } - - val externalFile = File(configFileName) - if (externalFile.exists() && externalFile.isFile) { - loadAndMergeImports(externalFile.readText()) - } else { - val resourceStream = AlchemistScript::class.java.classLoader - .getResourceAsStream(configFileName) - if (resourceStream != null) { - val json = resourceStream.bufferedReader().use { it.readText() } - loadAndMergeImports(json) - } + jvm { + dependenciesFromClassContext(AlchemistScript::class, wholeClasspath = true) + compilerOptions.append("-Xcontext-parameters") } - - return mergedImports +}) { + @Suppress("UnusedPrivateMember") + private fun readResolve(): Any = AlchemistCompilationConfiguration } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt index 9b78013340..6260052b43 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt @@ -31,14 +31,19 @@ import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromT object KotlinDslProvider : AlchemistLoaderProvider { override val fileExtensions: Regex = "(?i)kts".toRegex() - override fun from(input: String): Loader { - val host = BasicJvmScriptingHost() - val compilationConfiguration = createJvmCompilationConfigurationFromTemplate() - val evaluationConfiguration = ScriptEvaluationConfiguration { - jvm { - baseClassLoader(this@KotlinDslProvider::class.java.classLoader) - } + private val host = BasicJvmScriptingHost() + private val compilationConfiguration = createJvmCompilationConfigurationFromTemplate() + private val baseClassLoader = this::class.java.classLoader + + /** + * Evaluation configuration for script execution. + */ + private val evaluationConfiguration = ScriptEvaluationConfiguration { + jvm { + baseClassLoader(this@KotlinDslProvider.baseClassLoader) } + } + override fun from(input: String): Loader { val result = host.eval(input.toScriptSource(), compilationConfiguration, evaluationConfiguration) val errors = result.reports.filter { it.severity == ScriptDiagnostic.Severity.ERROR } require(errors.isEmpty()) { errors.joinToString("\n") { it.message } } diff --git a/alchemist-loading/src/main/resources/alchemist-default-imports.json b/alchemist-loading/src/main/resources/alchemist-default-imports.json deleted file mode 100644 index 47756c0812..0000000000 --- a/alchemist-loading/src/main/resources/alchemist-default-imports.json +++ /dev/null @@ -1,41 +0,0 @@ -[ - "it.unibo.alchemist.boundary.dsl.prelude.*", - "it.unibo.alchemist.boundary.dsl.Dsl.simulation", - "it.unibo.alchemist.boundary.dsl.Dsl.incarnation", - "it.unibo.alchemist.boundary.dsl.model.Incarnation.*", - "it.unibo.alchemist.boundary.dsl.generated.*", - "it.unibo.alchemist.model.maps.actions.*", - "it.unibo.alchemist.model.maps.deployments.*", - "it.unibo.alchemist.model.maps.environments.*", - "it.unibo.alchemist.model.*", - "it.unibo.alchemist.model.positions.*", - "it.unibo.alchemist.model.deployments.*", - "it.unibo.alchemist.model.positionfilters.And", - "it.unibo.alchemist.model.positionfilters.Or", - "it.unibo.alchemist.model.positionfilters.Not", - "it.unibo.alchemist.model.positionfilters.Xor", - "it.unibo.alchemist.model.actions.*", - "it.unibo.alchemist.model.conditions.*", - "it.unibo.alchemist.model.environments.*", - "it.unibo.alchemist.model.geometry.*", - "it.unibo.alchemist.model.layers.*", - "it.unibo.alchemist.model.linkingrules.*", - "it.unibo.alchemist.model.movestrategies.*", - "it.unibo.alchemist.model.neighborhoods.*", - "it.unibo.alchemist.model.nodes.*", - "it.unibo.alchemist.model.properties.*", - "it.unibo.alchemist.model.routes.*", - "it.unibo.alchemist.model.reactions.*", - "it.unibo.alchemist.model.terminators.*", - "it.unibo.alchemist.model.timedistributions.*", - "it.unibo.alchemist.boundary.properties.*", - "it.unibo.alchemist.boundary.dsl.aliases.*", - "it.unibo.alchemist.boundary.exporters.*", - "it.unibo.alchemist.boundary.extractors.*", - "it.unibo.alchemist.boundary.launchers.*", - "it.unibo.alchemist.boundary.statistic.*", - "it.unibo.alchemist.boundary.exportfilters.*", - "it.unibo.alchemist.boundary.variables.*", - "it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger" -] - diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 0a101673a9..29c1c00a36 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -22,8 +22,8 @@ import it.unibo.alchemist.boundary.dsl.generated.moleculeReader import it.unibo.alchemist.boundary.dsl.generated.point import it.unibo.alchemist.boundary.dsl.generated.testNode import it.unibo.alchemist.boundary.dsl.generated.testNodeProperty -import it.unibo.alchemist.boundary.dsl.model.Incarnation.PROTELIS -import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE +import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.PROTELIS +import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.SAPERE import it.unibo.alchemist.boundary.exporters.CSVExporter import it.unibo.alchemist.boundary.exportfilters.CommonFilters import it.unibo.alchemist.boundary.extractors.Time @@ -59,7 +59,7 @@ object DslLoaderFunctions { networkModel = ConnectWithinDistance(5.0) deployments { deploy(point(0.0, 0.0)) - deploy(Point(environment, 0.0, 1.0)) + deploy(Point(envAsAny, 0.0, 1.0)) } } } @@ -73,7 +73,7 @@ object DslLoaderFunctions { deployments { deploy( Circle( - environment, + envAsAny, generator, 10, 0.0, @@ -136,7 +136,7 @@ object DslLoaderFunctions { val hello = "hello" deploy( Grid( - environment, generator, + envAsAny, generator, -5.0, -5.0, 5.0, @@ -215,7 +215,7 @@ object DslLoaderFunctions { deployments { deploy( Grid( - environment, generator, + envAsAny, generator, -5.0, -5.0, 5.0, 5.0, 0.25, 0.25, 0.1, 0.1, ), ) { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt index 4c93058ed6..dc87170984 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -11,7 +11,7 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE +import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.SAPERE import it.unibo.alchemist.model.deployments.Point import it.unibo.alchemist.model.positions.Euclidean2DPosition import org.junit.jupiter.api.Test @@ -23,7 +23,7 @@ class TestContents { val incarnation = SAPERE.incarnation() val loader = simulation(incarnation) { deployments { - deploy(Point(environment, 0.0, 0.0)) { + deploy(Point(envAsAny, 0.0, 0.0)) { all { molecule = "test" concentration = 1.0 diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index bd60949acb..75fc0b8852 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -11,7 +11,7 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.dsl.model.Incarnation +import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point import it.unibo.alchemist.model.positions.Euclidean2DPosition @@ -21,10 +21,10 @@ class TestDeployments { @Test fun testDeployments() { - val incarnation = Incarnation.SAPERE.incarnation() + val incarnation = AvailableIncarnations.SAPERE.incarnation() val loader = simulation(incarnation) { deployments { - val p = Point(environment, 0.0, 0.0) + val p = Point(envAsAny, 0.0, 0.0) deploy(p) } } @@ -34,12 +34,12 @@ class TestDeployments { @Test fun testMultipleDeployments() { - val incarnation = Incarnation.SAPERE.incarnation() + val incarnation = AvailableIncarnations.SAPERE.incarnation() val loader = simulation(incarnation) { deployments { - val point = Point(environment, 0.0, 0.0) + val point = Point(envAsAny, 0.0, 0.0) deploy(point) - deploy(Point(environment, 1.0, 1.0)) + deploy(Point(envAsAny, 1.0, 1.0)) } } @@ -48,11 +48,11 @@ class TestDeployments { @Test fun testGridDeployment() { - val incarnation = Incarnation.SAPERE.incarnation() + val incarnation = AvailableIncarnations.SAPERE.incarnation() val loader = simulation(incarnation) { deployments { val grid = Grid( - environment, + envAsAny, generator, 1.0, 1.0, diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt index eea4791b6a..ed435d963c 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt @@ -11,7 +11,7 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE +import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.SAPERE import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.positions.Euclidean2DPosition import org.junit.jupiter.api.Test diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt index 413092ada8..a2a3a99bd6 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -15,12 +15,13 @@ import io.kotest.matchers.doubles.shouldBeExactly import io.kotest.matchers.shouldBe import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.dsl.model.Incarnation.SAPERE +import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.SAPERE +import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.model.Position import org.junit.jupiter.api.Test - +@Suppress("UNCHECKED_CAST") class TestVariables { @Test fun > testDefaultValue() { @@ -31,7 +32,8 @@ class TestVariables { runLater { println("Checking variable") rate.shouldBeExactly(5.0) - variablesContext.variables.containsKey("rate").shouldBeTrue() + (this@simulation as SimulationContextImpl).variablesContext + .variables.containsKey("rate").shouldBeTrue() } }.getDefault() // needed to build the simulation } @@ -43,19 +45,23 @@ class TestVariables { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) deployments { rate.shouldBeExactly(20.0) - variablesContext.variables.containsKey("rate").shouldBeTrue() + (this@simulation as SimulationContextImpl).variablesContext + .variables.containsKey("rate").shouldBeTrue() } } loader.getWith(mapOf(("rate" to 20.0))) } + @Suppress("NoNameShadowing") @Test fun > testDoubleDeclaration() { val incarnation = SAPERE.incarnation() simulation(incarnation) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + println("First declaration of rate: $rate") shouldThrow { val rate: Double by variable(GeometricVariable(2.0, 1.0, 5.0, 1)) + println("This line should not be printed: $rate") } } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts index eae1ee6177..bf2fcdef57 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts @@ -1,6 +1,4 @@ import another.location.SimpleMonitor -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation -import it.unibo.alchemist.boundary.dsl.Dsl.simulation /* * Copyright (C) 2010-2025, Danilo Pianini and contributors From f286d6cef577c17ce0d16c932ddbefc4d55055ab Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 10 Nov 2025 22:30:38 +0100 Subject: [PATCH 032/196] test: add performance tests --- .../dsl/PerformanceComparisonTest.kt | 164 ++++++++++++++++++ .../dsl/kts/19-performance.alchemist.kts | 110 ++++++++++++ .../test/resources/dsl/yml/19-performance.yml | 87 ++++++++++ 3 files changed, 361 insertions(+) create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt create mode 100644 alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts create mode 100644 alchemist-loading/src/test/resources/dsl/yml/19-performance.yml diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt new file mode 100644 index 0000000000..206f4777d6 --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt @@ -0,0 +1,164 @@ +package it.unibo.alchemist.dsl + +import it.unibo.alchemist.boundary.LoadAlchemist +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.model.Position +import java.io.File +import java.io.PrintStream +import java.util.Locale +import kotlin.time.measureTime +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Test +import org.kaikikm.threadresloader.ResourceLoader + +class PerformanceComparisonTest { + + private data class PerformanceStats( + val avgYamlTime: Double, + val avgDslTime: Double, + val minYamlTime: Long, + val minDslTime: Long, + val maxYamlTime: Long, + val maxDslTime: Long, + ) + + private fun calculateStats(yamlTimes: List, dslTimes: List): PerformanceStats = PerformanceStats( + avgYamlTime = yamlTimes.average(), + avgDslTime = dslTimes.average(), + minYamlTime = yamlTimes.minOrNull() ?: 0L, + minDslTime = dslTimes.minOrNull() ?: 0L, + maxYamlTime = yamlTimes.maxOrNull() ?: 0L, + maxDslTime = dslTimes.maxOrNull() ?: 0L, + ) + + private fun printResults(header: String, stats: PerformanceStats) { + println("\n=== $header ===") + println("YAML Loader:") + println(" Average: ${String.format(Locale.US, "%.2f", stats.avgYamlTime)} ms") + println(" Min: ${stats.minYamlTime} ms") + println(" Max: ${stats.maxYamlTime} ms") + println("\nDSL Loader:") + println(" Average: ${String.format(Locale.US, "%.2f", stats.avgDslTime)} ms") + println(" Min: ${stats.minDslTime} ms") + println(" Max: ${stats.maxDslTime} ms") + } + + private fun printSpeedup(stats: PerformanceStats, dslFasterMsg: String, yamlFasterMsg: String) { + val speedup = stats.avgYamlTime / stats.avgDslTime + println("\nSpeedup: ${String.format(Locale.US, "%.2f", speedup)}x") + if (speedup > 1.0) { + println("$dslFasterMsg ${String.format(Locale.US, "%.2f", speedup)}x faster than YAML") + } else { + println("$yamlFasterMsg ${String.format(Locale.US, "%.2f", 1.0 / speedup)}x faster than DSL") + } + } + + private fun runPerformanceTest( + testHeader: String, + yamlResource: String, + dslResource: String, + iterations: Int, + resultsHeader: String, + dslFasterMsg: String, + yamlFasterMsg: String, + yamlLoaderAction: (Loader) -> Unit, + dslLoaderAction: (Loader) -> Unit, + ) { + val originalOut = System.out + val originalErr = System.err + val nullStream = PrintStream(java.io.ByteArrayOutputStream()) + + println("\n=== $testHeader ===") + println("Resource: $yamlResource") + println("Iterations: $iterations\n") + + val yamlTimes = mutableListOf() + val dslTimes = mutableListOf() + + val dslUrl = ResourceLoader.getResource(dslResource)!! + val ymlUrl = ResourceLoader.getResource(yamlResource)!! + + repeat(iterations) { + System.setOut(nullStream) + System.setErr(nullStream) + + val yamlTime = measureTime { + val yamlLoader = LoadAlchemist.from(ymlUrl) + assertNotNull(yamlLoader) + yamlLoaderAction(yamlLoader) + } + + val dslTime = measureTime { + val dslLoader = LoadAlchemist.from(dslUrl) + assertNotNull(dslLoader) + dslLoaderAction(dslLoader) + } + + System.setOut(originalOut) + System.setErr(originalErr) + + yamlTimes.add(yamlTime.inWholeMilliseconds) + dslTimes.add(dslTime.inWholeMilliseconds) + } + + yamlTimes.forEachIndexed { index, time -> + println("Iteration ${index + 1}: YAML=${time}ms, DSL=${dslTimes[index]}ms") + } + + val stats = calculateStats(yamlTimes, dslTimes) + printResults(resultsHeader, stats) + printSpeedup(stats, dslFasterMsg, yamlFasterMsg) + + println("\n=== Test completed ===\n") + } + + @Test + fun > `performance comparison between YAML and DSL loaders`() { + runPerformanceTest( + testHeader = "Performance Test: YAML vs DSL Loader", + yamlResource = "dsl/yml/19-performance.yml", + dslResource = "dsl/kts/19-performance.alchemist.kts", + iterations = 5, + resultsHeader = "Results", + dslFasterMsg = "DSL is", + yamlFasterMsg = "YAML is", + yamlLoaderAction = { it.getDefault() }, + dslLoaderAction = { it.getDefault() }, + ) + } + + @Test + fun `performance comparison - loading phase only`() { + runPerformanceTest( + testHeader = "Performance Test: Loading Phase Only (YAML vs DSL)", + yamlResource = "dsl/yml/19-performance.yml", + dslResource = "dsl/kts/19-performance.alchemist.kts", + iterations = 10, + resultsHeader = "Results (Loading Phase Only)", + dslFasterMsg = "DSL loading is", + yamlFasterMsg = "YAML loading is", + yamlLoaderAction = {}, + dslLoaderAction = {}, + ) + } + + @Test + fun `verify both loaders produce equivalent results`() { + val yamlResource = "dsl/yml/19-performance.yml" + val dslResource = "/dsl/kts/19-performance.alchemist.kts" + + val dslUrl = requireNotNull(this.javaClass.getResource(dslResource)) { + "Resource $dslResource not found on test classpath" + } + val dslFile = File(dslUrl.toURI()) + + val yamlLoader = LoadAlchemist.from(ResourceLoader.getResource(yamlResource)!!) + val dslLoader = LoadAlchemist.from(dslFile) + + assertNotNull(yamlLoader) + assertNotNull(dslLoader) + + val dslLoaderFunction = { dslLoader } + dslLoaderFunction.shouldEqual(yamlResource, includeRuntime = false) + } +} diff --git a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts new file mode 100644 index 0000000000..b1a9a57187 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts @@ -0,0 +1,110 @@ + +import another.location.SimpleMonitor +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation +import it.unibo.alchemist.boundary.extractors.Time +import org.apache.commons.math3.random.MersenneTwister + +val incarnation = SAPERE.incarnation() +val environment = Continuous2DEnvironment(incarnation) +simulation(incarnation, environment) { + simulationGenerator = MersenneTwister(24L) + scenarioGenerator = MersenneTwister(42L) + + networkModel = ConnectWithinDistance(0.5) + + val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) + val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + + val mSize by variable { -size } + val sourceStart by variable { mSize / 10.0 } + val sourceSize by variable { size / 5.0 } + + layer { + molecule = "A" + layer = StepLayer(2.0, 2.0, 100.0, 0.0) + } + layer { + molecule = "B" + layer = StepLayer(-2.0, -2.0, 0.0, 100.0) + } + layer { + molecule = "C" + layer = StepLayer(0.0, 0.0, 50.0, 50.0) + } + + addMonitor(SimpleMonitor()) + + exporter { + type = CSVExporter( + "performance_test", + 1.0, + ) + data( + Time(), + moleculeReader( + "token", + null, + CommonFilters.NOFILTER.filteringPolicy, + emptyList(), + ), + ) + } + + deployments { + deploy( + circle( + 200, + 0.0, + 0.0, + 20.0, + ), + ) { + all { + molecule = "basemolecule" + } + inside(RectangleFilter(-5.0, -5.0, 10.0, 10.0)) { + molecule = "centermolecule" + } + programs { + all { + timeDistribution("1") + program = "{basemolecule} --> {processed}" + } + all { + program = "{processed} --> +{basemolecule}" + } + } + } + deploy( + grid( + mSize, mSize, size, size, + 0.25, 0.25, 0.1, 0.1, + ), + ) { + all { + molecule = "gridmolecule" + } + inside(RectangleFilter(sourceStart, sourceStart, sourceSize, sourceSize)) { + molecule = "token, 0, []" + } + inside(RectangleFilter(-2.0, -2.0, 4.0, 4.0)) { + molecule = "filteredmolecule" + } + programs { + all { + timeDistribution(rate.toString()) + program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" + } + all { + program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" + } + inside(RectangleFilter(-1.0, -1.0, 2.0, 2.0)) { + timeDistribution("0.5") + program = "{filteredmolecule} --> {active}" + } + } + } + } +} + diff --git a/alchemist-loading/src/test/resources/dsl/yml/19-performance.yml b/alchemist-loading/src/test/resources/dsl/yml/19-performance.yml new file mode 100644 index 0000000000..74068e27e3 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/yml/19-performance.yml @@ -0,0 +1,87 @@ +incarnation: sapere + +seeds: + scenario: 42 + simulation: 24 + +network-model: + type: ConnectWithinDistance + parameters: [0.5] + +environment: + type: Continuous2DEnvironment + parameters: [] + +variables: + rate: &rate + type: GeometricVariable + parameters: [2, 0.1, 10, 9] + size: &size + type: LinearVariable + parameters: [5, 1, 10, 1] + mSize: &mSize + formula: -size + sourceStart: &sourceStart + formula: mSize / 10 + sourceSize: &sourceSize + formula: size / 5 + +layers: + - type: StepLayer + parameters: [2, 2, 100, 0] + molecule: A + - type: StepLayer + parameters: [-2, -2, 0, 100] + molecule: B + - type: StepLayer + parameters: [0, 0, 50, 50] + molecule: C + +monitors: + - type: another.location.SimpleMonitor + +export: + - type: CSVExporter + parameters: + fileNameRoot: "performance_test" + interval: 1.0 + data: + - time + - molecule: "token" + +deployments: + - type: Circle + parameters: [200, 0, 0, 20] + contents: + - molecule: basemolecule + - in: + type: Rectangle + parameters: [-5, -5, 10, 10] + molecule: centermolecule + programs: + - time-distribution: 1 + program: "{basemolecule} --> {processed}" + - program: "{processed} --> +{basemolecule}" + - type: Grid + parameters: [*mSize, *mSize, *size, *size, 0.25, 0.25, 0.1, 0.1] + contents: + - molecule: gridmolecule + - in: + type: Rectangle + parameters: [*sourceStart, *sourceStart, *sourceSize, *sourceSize] + molecule: token, 0, [] + - in: + type: Rectangle + parameters: [-2, -2, 4, 4] + molecule: filteredmolecule + programs: + - time-distribution: *rate + program: "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" + - program: > + {token, N, L}{token, def: N2>=N, L2} --> {token, N, L} + - time-distribution: 0.5 + in: + type: Rectangle + parameters: [-1, -1, 2, 2] + program: "{filteredmolecule} --> {active}" + From 500c19c59baf907f51a085409c0f1be4d8b141aa Mon Sep 17 00:00:00 2001 From: marco Date: Sun, 16 Nov 2025 16:12:06 +0100 Subject: [PATCH 033/196] feat: add support for batch runs --- .../unibo/alchemist/boundary/dsl/BuildDsl.kt | 13 + .../unibo/alchemist/boundary/dsl/DSLLoader.kt | 88 ++++ .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 49 +- .../boundary/dsl/SingleUseDslLoader.kt | 80 ---- .../boundary/dsl/model/DeploymentContext.kt | 58 +-- .../dsl/model/DeploymentsContextImpl.kt | 43 +- .../boundary/dsl/model/ExporterContext.kt | 21 +- .../boundary/dsl/model/ExporterContextImpl.kt | 2 +- .../dsl/model/GlobalProgramsContext.kt | 44 ++ .../boundary/dsl/model/LayerContext.kt | 15 +- .../dsl/model/OutputMonitorsContext.kt | 44 ++ .../boundary/dsl/model/ProgramsContext.kt | 45 +- .../boundary/dsl/model/ProgramsContextImpl.kt | 56 ++- .../boundary/dsl/model/PropertiesContext.kt | 29 +- .../dsl/model/PropertiesContextImpl.kt | 5 +- .../boundary/dsl/model/SimulationContext.kt | 32 +- .../dsl/model/SimulationContextImpl.kt | 102 ++-- .../boundary/dsl/model/TerminatorsContext.kt | 47 ++ .../boundary/dsl/model/VariablesContext.kt | 38 +- .../boundary/dsl/util/LoadingSystemLogger.kt | 4 +- .../unibo/alchemist/model/nodes/TestNode.java | 2 +- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 163 +++++-- .../alchemist/dsl/KotlinDslProviderTest.kt | 2 +- .../alchemist/dsl/RuntimeComparisonHelper.kt | 434 +++++++++++++++--- .../alchemist/dsl/SimulationsComparisons.kt | 14 +- .../it/unibo/alchemist/dsl/TestComparators.kt | 153 +++++- .../it/unibo/alchemist/dsl/TestContents.kt | 2 +- .../it/unibo/alchemist/dsl/TestDeployments.kt | 8 +- .../it/unibo/alchemist/dsl/TestVariables.kt | 13 +- .../dsl/kts/11-monitors.alchemist.kts | 6 +- .../dsl/kts/15-variables.alchemist.kts | 1 + .../dsl/kts/18-properties.alchemist.kts | 8 +- .../dsl/kts/19-performance.alchemist.kts | 4 +- .../test/resources/dsl/yml/10-environment.yml | 2 +- .../src/test/resources/dsl/yml/20-move.yml | 22 + .../alchemist/test/GlobalTestReaction.kt | 2 + 36 files changed, 1175 insertions(+), 476 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/TerminatorsContext.kt create mode 100644 alchemist-loading/src/test/resources/dsl/yml/20-move.yml diff --git a/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt b/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt index 699fa9c551..1fa4e0daeb 100644 --- a/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt +++ b/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt @@ -16,6 +16,18 @@ package it.unibo.alchemist.boundary.dsl * * @param functionName Custom name for the generated DSL function. If empty, defaults to * the lowercase version of the class name with the first character lowercased. + * @param scope Manual override for the context type. Valid values (case-insensitive): + * - "SIMULATION" or "SIMULATION_CONTEXT" → SimulationContext + * - "EXPORTER" or "EXPORTER_CONTEXT" → ExporterContext + * - "GLOBAL_PROGRAMS" or "GLOBAL_PROGRAMS_CONTEXT" → GlobalProgramsContext + * - "OUTPUT_MONITORS" or "OUTPUT_MONITORS_CONTEXT" → OutputMonitorsContext + * - "TERMINATORS" or "TERMINATORS_CONTEXT" → TerminatorsContext + * - "DEPLOYMENT" or "DEPLOYMENTS_CONTEXT" → DeploymentsContext + * - "DEPLOYMENT_CONTEXT" → DeploymentContext (singular) + * - "PROGRAM" or "PROGRAM_CONTEXT" → ProgramContext + * - "PROPERTY" or "PROPERTY_CONTEXT" → PropertyContext + * If empty, the context type is automatically determined based on the constructor parameters. + * This allows manual context passing to override the default behavior. * @param injectEnvironment Whether to inject an Environment parameter into the generated builder function. * @param injectGenerator Whether to inject a Generator parameter into the generated builder function. * @param injectNode Whether to inject a Node parameter into the generated builder function. @@ -25,6 +37,7 @@ package it.unibo.alchemist.boundary.dsl @Retention(AnnotationRetention.SOURCE) annotation class BuildDsl( val functionName: String = "", + val scope: String = "", val injectEnvironment: Boolean = true, val injectGenerator: Boolean = true, val injectNode: Boolean = true, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt new file mode 100644 index 0000000000..660cc068ff --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl + +import it.unibo.alchemist.boundary.Exporter +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl +import it.unibo.alchemist.boundary.exporters.GlobalExporter +import it.unibo.alchemist.core.Engine +import it.unibo.alchemist.core.Simulation +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Position +import java.util.concurrent.Semaphore + +/** + * Abstract base class for single-use DSL loaders. + * + * @param ctx The simulation context. + */ +abstract class DSLLoader>( + private val ctx: SimulationContextImpl<*, *>, + private val envFactory: () -> Environment<*, *>, +) : Loader { + override fun > getWith(values: Map): Simulation = + SingleUseLoader(ctx).load(values) + private inner class SingleUseLoader(private val ctx: SimulationContextImpl<*, *>) { + private val mutex = Semaphore(1) + private var consumed = false + + @Suppress("UNCHECKED_CAST") + fun > load(values: Map): Simulation { + try { + mutex.acquireUninterruptibly() + check(!consumed) { "This loader has already been consumed! This is a bug in Alchemist" } + consumed = true + } finally { + mutex.release() + } + val typedCtx = ctx as SimulationContextImpl + val envInstance = envFactory() as Environment + println("Environment instance: $envInstance") + println("applying dsl with values $values") + println("Build steps" + ctx.buildSteps) + + val unknownVariableNames = values.keys - this@DSLLoader.variables.keys + require(unknownVariableNames.isEmpty()) { + "Unknown variables provided: $unknownVariableNames." + + " Valid names: ${this@DSLLoader.variables.keys}. Provided: ${values.keys}" + } + // VARIABLE REIFICATION + ctx.variablesContext.addReferences( + ctx.variablesContext.dependentVariables.map { (k, v) -> + k to v() + }.toMap(), + ) + + val simulationIstance = typedCtx.build(envInstance, values) + val environment = simulationIstance.environment + val engine = Engine(environment) + + // MONITORS + simulationIstance.monitors.forEach { monitor -> + engine.addOutputMonitor(monitor) + } + // EXPORTERS + val exporters = simulationIstance.exporters.map { + it.type.apply { + it.type?.bindDataExtractors(it.extractors) + } + } as List> + + exporters.forEach { it.bindVariables(ctx.variablesContext.references.get()) } + + if (exporters.isNotEmpty()) { + engine.addOutputMonitor(GlobalExporter(exporters)) + } + + return engine + } + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index b813c65c5a..4a01f97d85 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -24,8 +24,20 @@ import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.positions.Euclidean2DPosition import kotlin.jvm.optionals.getOrElse +/** + * Marker annotation for Alchemist DSL elements. + * + * This annotation is used to mark DSL context classes and functions, + * preventing scope pollution in DSL blocks. + */ +@DslMarker +annotation class AlchemistDsl + /** * Main DSL object for creating Alchemist simulations. + * + * This object provides factory methods for creating simulation loaders + * and configuring Alchemist simulations using a type-safe DSL. */ object Dsl { /** @@ -34,12 +46,15 @@ object Dsl { * @param dsl The simulation context. * @return A loader instance. */ - fun > createLoader(dsl: SimulationContextImpl): Loader = object : SingleUseDslLoader(dsl) { - override val constants: Map = emptyMap() // not needed - override val dependentVariables: Map> = emptyMap() // not needed - override val variables: Map> = dsl.variablesContext.variables - override val remoteDependencies: List = emptyList() // not needed - override val launcher: Launcher = dsl.launcher + fun > createLoader( + builder: SimulationContextImpl, + envBuilder: () -> Environment, + ): Loader = object : DSLLoader(builder, envBuilder) { + override val constants: Map = emptyMap() + override val dependentVariables: Map> = emptyMap() + override val variables: Map> = builder.variablesContext.variables + override val remoteDependencies: List = emptyList() + override val launcher: Launcher = builder.launcher } /** @@ -62,15 +77,13 @@ object Dsl { */ fun > simulation( incarnation: Incarnation, - environment: Environment, + environment: () -> Environment, block: SimulationContext.() -> Unit, ): Loader { - val ctx = SimulationContextImpl(incarnation, environment) + val ctx = SimulationContextImpl(incarnation) @Suppress("UNCHECKED_CAST") - context(ctx.environment as Environment<*, *>, ctx.incarnation as Incarnation<*, *>) { - ctx.apply(block) - } - return createLoader(ctx) + ctx.apply(block) + return createLoader(ctx, environment) } /** @@ -81,16 +94,14 @@ object Dsl { * @return A loader instance. */ fun > simulation( - incarnation: Incarnation, + incarnation: Incarnation, block: SimulationContext.() -> Unit, ): Loader { @Suppress("UNCHECKED_CAST") - val defaultEnv = Continuous2DEnvironment(incarnation as Incarnation) - val ctx = SimulationContextImpl(incarnation, defaultEnv) + val defaultEnv = { Continuous2DEnvironment(incarnation) } + val ctx = SimulationContextImpl(incarnation) @Suppress("UNCHECKED_CAST") - context(ctx.environment, ctx.incarnation) { - ctx.apply(block) - } - return createLoader(ctx) + ctx.apply(block) + return createLoader(ctx, defaultEnv) } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt deleted file mode 100644 index ed2d9ddb1b..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/SingleUseDslLoader.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl - -import it.unibo.alchemist.boundary.Exporter -import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.OutputMonitor -import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl -import it.unibo.alchemist.boundary.exporters.GlobalExporter -import it.unibo.alchemist.core.Engine -import it.unibo.alchemist.core.Simulation -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Position -import java.util.concurrent.Semaphore - -/** - * Abstract base class for single-use DSL loaders. - * - * @param ctx The simulation context. - */ -abstract class SingleUseDslLoader(private val ctx: SimulationContextImpl<*, *>) : Loader { - private val mutex = Semaphore(1) - private var consumed = false - - @Suppress("UNCHECKED_CAST") - override fun > getWith(values: Map): Simulation { - try { - mutex.acquireUninterruptibly() - check(!consumed) { "This loader has already been consumed! This is a bug in Alchemist" } - consumed = true - } finally { - mutex.release() - } - values.forEach { (t, u) -> - ctx.variablesContext.references[t] = u as Any - } - println("applying dsl with this values" + ctx.variablesContext.references) - println("Build steps" + ctx.buildSteps) - ctx.build() // variables passing - val environment = ctx.environment as Environment - val engine = Engine(environment) - val unknownVariableNames = values.keys - variables.keys - require(unknownVariableNames.isEmpty()) { - "Unknown variables provided: $unknownVariableNames." + - " Valid names: ${variables.keys}. Provided: ${values.keys}" - } - // VARIABLE REIFICATION - val variableValues = ctx.variablesContext.references.plus( - ctx.variablesContext.dependentVariables.map { (k, v) -> - k to v() - }, - ) - - // MONITORS - ctx.monitors.forEach { monitor -> - engine.addOutputMonitor(monitor as OutputMonitor) - } - // EXPORTERS - val exporters = ctx.exporters.map { - it.type.apply { - it.type?.bindDataExtractors(it.extractors) - } - } as List> - - exporters.forEach { it.bindVariables(variableValues) } - - if (exporters.isNotEmpty()) { - engine.addOutputMonitor(GlobalExporter(exporters)) - } - - return engine - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt index 5e2a7d0f43..759e67d2b0 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt @@ -9,8 +9,8 @@ package it.unibo.alchemist.boundary.dsl.model +import it.unibo.alchemist.boundary.dsl.AlchemistDsl import it.unibo.alchemist.model.Deployment -import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter @@ -49,37 +49,13 @@ import org.apache.commons.math3.random.RandomGenerator * @see [Deployment] for the deployment interface * @see [DeploymentContext] for configuring individual deployments */ -@DslMarker -annotation class DeploymentsMarker - -/** - * Context interface for managing node deployments in a simulation. - * - * Deployments define where nodes are placed in the environment and can be configured - * with content (molecules and concentrations), programs (reactions), and properties. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - */ -@DeploymentsMarker +@AlchemistDsl interface DeploymentsContext> { /** * The simulation context this deployments context belongs to. */ val ctx: SimulationContext - /** - * The environment instance as a type-erased reference. - */ - val envAsAny: Environment<*, *> - - /** - * The environment instance where nodes are deployed. - * - * @see [Environment] - */ - val env: Environment - /** * The random number generator for scenario generation. * @@ -131,19 +107,7 @@ interface DeploymentsContext> { * @see [ProgramsContext] for configuring node programs * @see [PropertiesContext] for configuring node properties */ -@DslMarker -annotation class DeploymentMarker - -/** - * Context interface for configuring a single deployment. - * - * This context allows configuring content (molecules and concentrations), programs (reactions), - * properties, and custom node factories for nodes deployed at positions defined by the deployment. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - */ -@DeploymentMarker +@AlchemistDsl interface DeploymentContext> { /** * The deployments context this deployment context belongs to. @@ -217,7 +181,7 @@ interface DeploymentContext> { * @see [Node] * @see [it.unibo.alchemist.model.Incarnation.createNode] */ - fun nodes(factory: () -> Node) + fun nodes(factory: (DeploymentContext) -> Node) /** * Configures properties for this deployment. @@ -251,19 +215,7 @@ interface DeploymentContext> { * @see [it.unibo.alchemist.model.Incarnation.createMolecule] * @see [it.unibo.alchemist.model.Incarnation.createConcentration] */ -@DslMarker -annotation class ContentMarker - -/** - * Context interface for configuring node content (molecules and concentrations). - * - * This context is used within [DeploymentContext] blocks to define the initial - * content of nodes deployed at specific positions. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - */ -@ContentMarker +@AlchemistDsl interface ContentContext> { /** * The optional position filter applied to this content context. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt index 40f29c2ed4..ea25cdff40 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt @@ -10,13 +10,14 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger +import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Deployment -import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter import it.unibo.alchemist.model.linkingrules.CombinedLinkingRule import it.unibo.alchemist.model.linkingrules.NoLinks +import org.apache.commons.math3.random.RandomGenerator /** * Context for managing deployments in a simulation. @@ -27,23 +28,13 @@ import it.unibo.alchemist.model.linkingrules.NoLinks */ open class DeploymentsContextImpl>(override val ctx: SimulationContext) : DeploymentsContext { - /** - * The environment instance. - */ - override val envAsAny: Environment<*, *> = ctx.environment as Environment<*, *> - /** - * The environment instance. - */ - override val env = ctx.environment + override val generator: RandomGenerator + get() = ctx.scenarioGenerator - /** - * The scenario generator. - */ - override val generator = ctx.scenarioGenerator private val inc = ctx.incarnation - override fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) { + override fun deploy(deployment: Deployment<*>, block: context(DeploymentContext) () -> Unit) { logger.debug("Deploying deployment: {}", deployment) @Suppress("UNCHECKED_CAST") val d = DeploymentContextImpl(deployment as Deployment

).apply(block) @@ -70,10 +61,10 @@ open class DeploymentsContextImpl>(override val ctx: Simulati deployment.stream().forEach { position -> logger.debug("visiting position: {} for deployment: {}", position, deployment) logger.debug("creaing node for deployment: {}", deployment) - val node = deploymentContext.nodeFactory?.invoke() + val node = deploymentContext.nodeFactory?.invoke(deploymentContext) ?: inc.createNode( - ctx.simulationGenerator, - env, + ctx.simulationGenerator, // Match YAML loader: uses simulationRNG for node creation + ctx.environment, null, ) // load properties @@ -85,16 +76,19 @@ open class DeploymentsContextImpl>(override val ctx: Simulati } // load programs val programs = deploymentContext.programsContext.programs + val createdPrograms = mutableListOf?, Actionable>>() for (programEntry in programs) { - deploymentContext.programsContext.applyToNodes( + val pp = deploymentContext.programsContext.applyToNodes( node, position, programEntry.program, programEntry.filter, ) + createdPrograms.add(pp) } + logger.debug("programs={}", createdPrograms) logger.debug("Adding node to environment at position: {}", position) - env.addNode(node, position) + ctx.environment.addNode(node, position) } } @@ -114,7 +108,10 @@ open class DeploymentsContextImpl>(override val ctx: Simulati /** * Optional factory for creating custom nodes. */ - var nodeFactory: (() -> Node)? = null + var nodeFactory: ( + context(DeploymentContext) + () -> Node + )? = null /** * The properties context for this deployment. @@ -147,7 +144,7 @@ open class DeploymentsContextImpl>(override val ctx: Simulati programsContext.apply(block) } - override fun nodes(factory: () -> Node) { + override fun nodes(factory: DeploymentContext.() -> Node) { nodeFactory = factory } @@ -166,12 +163,12 @@ open class DeploymentsContextImpl>(override val ctx: Simulati logger.debug("Applying node to nodes for position: {}, deployment {}", position, deployment) if (content.filter == null || content.filter.contains(position)) { logger.debug("Creating molecule for node at position: {}", position) - val mol = inc.createMolecule( + val mol = ctx.ctx.incarnation.createMolecule( content.molecule ?: error("Molecule not specified"), ) logger.debug("Creating concentration for molecule: {}", mol) - val conc = inc.createConcentration(content.concentration) + val conc = ctx.ctx.incarnation.createConcentration(content.concentration) logger.debug("Setting concentration for molecule: {} to node at position: {}", mol, position) node.setConcentration(mol, conc) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt index 0243cd07d4..68e67625c7 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt @@ -11,6 +11,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.Exporter import it.unibo.alchemist.boundary.Extractor +import it.unibo.alchemist.boundary.dsl.AlchemistDsl import it.unibo.alchemist.model.Position /** @@ -37,22 +38,12 @@ import it.unibo.alchemist.model.Position * @see [Exporter] for the exporter interface * @see [Extractor] for data extraction */ -@DslMarker -annotation class ExporterMarker - -/** - * Context interface for configuring data exporters in a simulation. - * - * Exporters define how simulation data is extracted and exported, supporting formats - * such as CSV, MongoDB, and custom formats. - * Data can be exported per-node or aggregated - * using statistical functions. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - */ -@ExporterMarker +@AlchemistDsl interface ExporterContext> { + + /** The parent simulation context. */ + val ctx: SimulationContext + /** * The exporter instance that handles data output. * diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt index 685ec6eb35..45d3a2c853 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt @@ -19,7 +19,7 @@ import it.unibo.alchemist.model.Position * @param T The type of molecule concentration. * @param P The type of position. */ -class ExporterContextImpl> : ExporterContext { +class ExporterContextImpl>(override val ctx: SimulationContext) : ExporterContext { override var type: Exporter? = null /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt new file mode 100644 index 0000000000..472752a80b --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.model.GlobalReaction +import it.unibo.alchemist.model.Position + +/** + * Context for configuring global reactions in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +interface GlobalProgramsContext> { + /** The parent simulation context. */ + val ctx: SimulationContext + + /** + * Adds a global reaction to the simulation. + * + * @param this The global reaction to add. + */ + operator fun GlobalReaction.unaryPlus() +} + +/** + * Implementation of [GlobalProgramsContext]. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +class GlobalProgramsContextImpl>(override val ctx: SimulationContext) : + GlobalProgramsContext { + override fun GlobalReaction.unaryPlus() { + ctx.environment.addGlobalReaction(this) + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt index 3e8f7ec20b..67f9f4b116 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt @@ -9,6 +9,7 @@ package it.unibo.alchemist.boundary.dsl.model +import it.unibo.alchemist.boundary.dsl.AlchemistDsl import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.Position @@ -33,19 +34,7 @@ import it.unibo.alchemist.model.Position * @see [SimulationContext.layer] for adding layers to a simulation * @see [Layer] for the layer interface */ -@DslMarker -annotation class LayerMarker - -/** - * Context interface for configuring spatial layers in a simulation. - * - * Layers define overlays of data that can be sensed everywhere in the environment. - * They can be used to model physical properties such as pollution, light, temperature, etc. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - */ -@LayerMarker +@AlchemistDsl interface LayerContext> { /** * The molecule name associated with this layer. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt new file mode 100644 index 0000000000..4d607c4aeb --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.OutputMonitor +import it.unibo.alchemist.model.Position + +/** + * Context for configuring output monitors in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +interface OutputMonitorsContext> { + /** The parent simulation context. */ + val ctx: SimulationContext + + /** + * Adds an output monitor to the simulation. + * + * @param this The output monitor to add. + */ + operator fun OutputMonitor.unaryPlus() +} + +/** + * Implementation of [OutputMonitorsContext]. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +class OutputMonitorsContextImpl>(override val ctx: SimulationContextImpl) : + OutputMonitorsContext { + override fun OutputMonitor.unaryPlus() { + ctx.monitors += this + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt index 9dea1409f2..ebd4dc072c 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt @@ -9,6 +9,7 @@ package it.unibo.alchemist.boundary.dsl.model +import it.unibo.alchemist.boundary.dsl.AlchemistDsl import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Condition import it.unibo.alchemist.model.Node @@ -48,19 +49,7 @@ import it.unibo.alchemist.model.TimeDistribution * @see [Reaction] for the reaction interface * @see [TimeDistribution] for time distribution configuration */ -@DslMarker -annotation class ProgramsMarker - -/** - * Context interface for configuring programs (reactions) in a deployment. - * - * Programs define the behavior of nodes through reactions that execute actions - * when conditions are met. Programs can be applied to all nodes or filtered by position. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - */ -@ProgramsMarker +@AlchemistDsl interface ProgramsContext> { /** * The deployment context this programs context belongs to. @@ -101,19 +90,7 @@ interface ProgramsContext> { * @see [Action] for reaction actions * @see [Condition] for reaction conditions */ -@DslMarker -annotation class ProgramMarker - -/** - * Context interface for configuring a single program (reaction) for a node. - * - * This context is used within [ProgramsContext] blocks to define reactions with - * their time distributions, conditions, and actions. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - */ -@ProgramMarker +@AlchemistDsl interface ProgramContext> { /** * The programs context this program context belongs to. @@ -173,6 +150,14 @@ interface ProgramContext> { */ fun addAction(block: () -> Action) + /** + * Adds an action to the program using the incarnation createAction function. + * + * @param action the action + * @see [it.unibo.alchemist.model.Incarnation.createAction] + */ + fun addAction(action: String) + /** * Adds a condition to the program. * @@ -183,6 +168,14 @@ interface ProgramContext> { */ fun addCondition(block: () -> Condition) + /** + * Adds a condition to the program, using the incarnation createCondition function. + * + * @param condition the condition + * @see [it.unibo.alchemist.model.Incarnation.createCondition] + */ + fun addCondition(condition: String) + /** * Unary plus operator for type-safe casting of [TimeDistribution]. * diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt index d28b8b9562..d72e1881d1 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt @@ -2,6 +2,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.model.Action +import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Condition import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position @@ -56,13 +57,11 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex position: P, program: ProgramContextImpl.() -> Unit, filter: PositionBasedFilter

?, - ) { + ): Pair?, Actionable> { logger.debug("Applying program to node at position: {}", position) val c = ProgramContextImpl(node).apply(program) val context = ctx.ctx.ctx - if (filter != null && !filter.contains(position)) { - return - } + logger.debug("Creating time distribution for program") val timeDistribution = c.timeDistribution ?: context.incarnation.createTimeDistribution( @@ -72,8 +71,8 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex null, ) logger.debug("Creating reaction for program") - val r = c.reaction ?: run { - // Create a basic reaction with custom actions/conditions + val r = c.reaction + ?: // Create a basic reaction with custom actions/conditions context.incarnation.createReaction( context.simulationGenerator, context.environment, @@ -81,25 +80,28 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex timeDistribution, c.program, ) - } logger.debug("Adding actions to reaction") r.actions += c.actions.map { it() } logger.debug("Adding conditions to reaction") r.conditions += c.conditions.map { it() } - logger.debug("Adding condition to reaction") - node.addReaction(r) + logger.debug("Adding reaction to node") + if (filter == null || filter.contains(position)) { + node.addReaction(r) + } + return filter to r } /** * Context for configuring a single program (reaction). * * @param node The node this program is associated with. - * @param ctx The programs context. + * @param ctx The programs' context. */ open inner class ProgramContextImpl(override val node: Node) : ProgramContext { override val ctx: ProgramsContext = this@ProgramsContextImpl + private val context = ctx.ctx.ctx.ctx /** * The program name. @@ -127,10 +129,9 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex override var reaction: Reaction? = null override fun timeDistribution(td: String) { - val c = ctx.ctx.ctx.ctx - timeDistribution = c.incarnation.createTimeDistribution( - c.simulationGenerator, - c.environment, + timeDistribution = context.incarnation.createTimeDistribution( + context.simulationGenerator, + context.environment, node, td, ) @@ -140,8 +141,35 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex actions += block } + override fun addAction(action: String) { + actions += { + context.incarnation + .createAction( + context.simulationGenerator, + context.environment, + node, + timeDistribution, + reaction, + action, + ) + } + } + override fun addCondition(block: () -> Condition) { conditions += block } + + override fun addCondition(condition: String) { + conditions += { + context.incarnation.createCondition( + context.simulationGenerator, + context.environment, + node, + timeDistribution, + reaction, + condition, + ) + } + } } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt index b124401c04..fd237670d6 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt @@ -9,6 +9,7 @@ package it.unibo.alchemist.boundary.dsl.model +import it.unibo.alchemist.boundary.dsl.AlchemistDsl import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.NodeProperty import it.unibo.alchemist.model.Position @@ -44,19 +45,8 @@ import it.unibo.alchemist.model.PositionBasedFilter * @see [NodeProperty] for the property interface * @see [PositionBasedFilter] for position filtering */ -@DslMarker -annotation class PropertiesMarker -/** - * Context interface for configuring node properties in a deployment. - * - * Properties can be assigned to nodes based on their position using filters, - * or applied to all nodes in the deployment. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - */ -@PropertiesMarker +@AlchemistDsl interface PropertiesContext> { /** * The deployment context this properties context belongs to. @@ -93,18 +83,7 @@ interface PropertiesContext> { * @see [PropertiesContext] for the parent context * @see [NodeProperty] for the property interface */ -@DslMarker -annotation class PropertyMarker - -/** - * Context interface for configuring properties for a specific node. - * - * This context is used within [PropertiesContext] blocks to add properties to nodes. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - */ -@PropertyMarker +@AlchemistDsl interface PropertyContext> { /** * The properties context this property context belongs to. @@ -127,5 +106,5 @@ interface PropertyContext> { * @param property The property to add to the node. * @see [NodeProperty] */ - fun add(property: NodeProperty) + operator fun NodeProperty.unaryPlus() } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt index c9f7b6638b..cbe494b978 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt @@ -65,9 +65,8 @@ class PropertiesContextImpl>(override val ctx: DeploymentCont */ val properties: MutableList> = mutableListOf() - override fun add(property: NodeProperty) { - logger.debug("Adding property: {}", property) - properties.add(property) + override operator fun NodeProperty.unaryPlus() { + properties.add(this) } } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index d63184107e..166942f76a 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -12,6 +12,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.Variable +import it.unibo.alchemist.boundary.dsl.AlchemistDsl import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GlobalReaction @@ -54,20 +55,7 @@ import org.apache.commons.math3.random.RandomGenerator * @see [ExporterContextImpl] for exporter configuration * @see [LayerContextImpl] for layer configuration */ -@DslMarker -annotation class SimulationMarker - -/** - * Main context interface for building and configuring Alchemist simulations using the DSL. - * - * This interface provides a type-safe way to configure simulations programmatically. - * It serves as the entry point for DSL users to define - * all aspects of a simulation including deployments, programs, monitors, exporters, and more. - * - * @param T The type of molecule concentration used in the simulation - * @param P The type of position used in the environment, must extend [Position] - */ -@SimulationMarker +@AlchemistDsl interface SimulationContext> { /** * The incarnation instance that defines how molecules, nodes, and reactions are created. @@ -139,7 +127,7 @@ interface SimulationContext> { * * @see [DeploymentsContextImpl] to configure deployments */ - fun deployments(block: DeploymentsContextImpl.() -> Unit) + fun deployments(block: DeploymentsContext.() -> Unit) /** * Adds a termination predicate to the simulation. @@ -147,7 +135,7 @@ interface SimulationContext> { * @param terminator The termination predicate to add * @see [TerminationPredicate] */ - fun addTerminator(terminator: TerminationPredicate<*, *>) + fun terminators(block: TerminatorsContext.() -> Unit) /** * Adds an output monitor to the simulation. @@ -155,7 +143,7 @@ interface SimulationContext> { * @param monitor The output monitor to add * @see [OutputMonitor] */ - fun addMonitor(monitor: OutputMonitor) + fun monitors(block: OutputMonitorsContext.() -> Unit) /** * Add an exporter to the simulation for data output. @@ -171,7 +159,7 @@ interface SimulationContext> { * @param program the global reaction to add * @see [GlobalReaction] */ - fun program(program: GlobalReaction) + fun programs(block: GlobalProgramsContext.() -> Unit) /** * Schedules a block of code to execute later during the loading process. @@ -189,7 +177,7 @@ interface SimulationContext> { * * @param block The block of code to execute later */ - fun runLater(block: () -> Unit) + fun runLater(block: context(SimulationContext) () -> Unit) /** * Add a spatial layer for a molecule. @@ -200,7 +188,7 @@ interface SimulationContext> { * @param block The configuration block * @see [LayerContextImpl] */ - fun layer(block: LayerContextImpl.() -> Unit) + fun layer(block: LayerContext.() -> Unit) /** * Registers a Linear Variable for batch simulations. @@ -213,7 +201,7 @@ interface SimulationContext> { * @param source The variable source that provides the range of values * @see [Variable] */ - fun variable(source: Variable): VariablesContext.VariableProvider + fun variable(source: Variable): VariablesContext.VariableProvider /** * Registers a dependent variable that is computed from other variables. @@ -226,5 +214,5 @@ interface SimulationContext> { * * @param source A function that computes the variable value */ - fun variable(source: () -> T): VariablesContext.DependentVariableProvider + fun variable(source: () -> A): VariablesContext.DependentVariableProvider } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt index fec3a01c4e..8965c566c5 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -17,13 +17,10 @@ import it.unibo.alchemist.boundary.Variable import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.boundary.launchers.DefaultLauncher import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.GlobalReaction import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.TerminationPredicate -import it.unibo.alchemist.model.linkingrules.NoLinks import java.io.Serializable import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator @@ -35,14 +32,16 @@ import org.apache.commons.math3.random.RandomGenerator * @param P The type of position. */ -class SimulationContextImpl>( - override val incarnation: Incarnation, - override val environment: Environment, -) : SimulationContext { +class SimulationContextImpl>(override val incarnation: Incarnation) : SimulationContext { + /** The environment instance (internal use). */ + var envIstance: Environment? = null + override val environment: Environment + get() = requireNotNull(envIstance) { "Environment has not been initialized yet" } + /** * List of build steps to execute. */ - val buildSteps: MutableList<() -> Unit> = mutableListOf() + val buildSteps: MutableList.() -> Unit> = mutableListOf() /** * List of output . @@ -56,18 +55,42 @@ class SimulationContextImpl>( override var launcher: Launcher = DefaultLauncher() - override var scenarioGenerator: RandomGenerator = MersenneTwister(0L) + /** + * Map of variable references. + */ + val references: MutableMap = mutableMapOf() + + private var _scenarioGenerator: RandomGenerator? = null + private var _simulationGenerator: RandomGenerator? = null - override var simulationGenerator: RandomGenerator = MersenneTwister(0L) + override var scenarioGenerator: RandomGenerator + get() = if (_scenarioGenerator == null) { + _scenarioGenerator = MersenneTwister(0L) + _scenarioGenerator!! + } else { + _scenarioGenerator!! + } + set(value) { + buildSteps.add { this._scenarioGenerator = value } + } + + override var simulationGenerator: RandomGenerator + get() = if (_simulationGenerator == null) { + _simulationGenerator = MersenneTwister(0L) + _simulationGenerator!! + } else { + _simulationGenerator!! + } + set(value) { + buildSteps.add { this._simulationGenerator = value } + } private val layers: MutableMap> = HashMap() - private var _networkModel: LinkingRule = NoLinks() override var networkModel: LinkingRule - get() = _networkModel + get() = environment.linkingRule set(value) { - _networkModel = value - environment.linkingRule = value + buildSteps.add { this.environment.linkingRule = value } } /** @@ -76,38 +99,53 @@ class SimulationContextImpl>( val variablesContext = VariablesContext() /** - * Executes all build steps. + * Build a fresh new simulation context instance, and applies + * all the build steps to it. + * To ensure that each instance has + * its own variables spaces: check the [VariablesContext] documentation for more details. + * @see [VariablesContext] */ - fun build() { - buildSteps.forEach { it() } + fun build(envInstance: Environment, values: Map): SimulationContextImpl { + val batchContext = SimulationContextImpl(incarnation) + batchContext.envIstance = envInstance + batchContext.variablesContext.variables += this.variablesContext.variables + batchContext.variablesContext.dependentVariables += this.variablesContext.dependentVariables + logger.debug("Binding variables to batchInstance: {}", values) + this.variablesContext.addReferences(values) + buildSteps.forEach { batchContext.apply(it) } + return batchContext } - override fun deployments(block: DeploymentsContextImpl.() -> Unit) { - buildSteps.add { DeploymentsContextImpl(this).apply(block) } + override fun deployments(block: DeploymentsContext.() -> Unit) { + logger.debug("adding deployments block inside {}", this) + buildSteps.add { + logger.debug("Configuring deployments inside {}", this) + DeploymentsContextImpl(this).apply(block) + } } - override fun addTerminator(terminator: TerminationPredicate<*, *>) { + override fun terminators(block: TerminatorsContext.() -> Unit) { @Suppress("UNCHECKED_CAST") - buildSteps.add { environment.addTerminator(terminator as TerminationPredicate) } + buildSteps.add { TerminatorsContextImpl(this).block() } } - override fun addMonitor(monitor: OutputMonitor) { - buildSteps.add { monitors.add(monitor) } + override fun monitors(block: OutputMonitorsContext.() -> Unit) { + buildSteps.add { OutputMonitorsContextImpl(this).block() } } override fun exporter(block: ExporterContextImpl.() -> Unit) { - buildSteps.add { exporters.add(ExporterContextImpl().apply(block)) } + buildSteps.add { this.exporters.add(ExporterContextImpl(this).apply(block)) } } - override fun program(program: GlobalReaction) { - buildSteps.add { this.environment.addGlobalReaction(program) } + override fun programs(block: GlobalProgramsContext.() -> Unit) { + buildSteps.add { GlobalProgramsContextImpl(this).block() } } - override fun runLater(block: () -> Unit) { + override fun runLater(block: context(SimulationContext)() -> Unit) { buildSteps.add { block() } } - override fun layer(block: LayerContextImpl.() -> Unit) { + override fun layer(block: LayerContext.() -> Unit) { buildSteps.add { val l = LayerContextImpl().apply(block) val layer = requireNotNull(l.layer) { "Layer must be specified" } @@ -118,14 +156,14 @@ class SimulationContextImpl>( } val molecule = incarnation.createMolecule(moleculeName) logger.debug("Adding layer for molecule {}: {}", moleculeName, layer) - layers[moleculeName] = layer - environment.addLayer(molecule, layer) + this.layers[moleculeName] = layer + this.environment.addLayer(molecule, layer) } } - override fun variable(source: Variable): VariablesContext.VariableProvider = + override fun variable(source: Variable): VariablesContext.VariableProvider = variablesContext.register(source) - override fun variable(source: () -> T): VariablesContext.DependentVariableProvider = + override fun variable(source: () -> A): VariablesContext.DependentVariableProvider = variablesContext.dependent(source) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/TerminatorsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/TerminatorsContext.kt new file mode 100644 index 0000000000..2a0bc66008 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/TerminatorsContext.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.dsl.AlchemistDsl +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.TerminationPredicate + +/** + * Context for configuring termination predicates in a simulation. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +@AlchemistDsl +interface TerminatorsContext> { + /** The parent simulation context. */ + val ctx: SimulationContext + + /** + * Adds a termination predicate to the simulation. + * + * @param this The termination predicate to add. + */ + operator fun TerminationPredicate<*, *>.unaryPlus() +} + +/** + * Implementation of [TerminatorsContext]. + * + * @param T The type of molecule concentration. + * @param P The type of position. + */ +class TerminatorsContextImpl>(override val ctx: SimulationContext) : + TerminatorsContext { + @Suppress("UNCHECKED_CAST") + override fun TerminationPredicate<*, *>.unaryPlus() { + ctx.environment.addTerminator(this as TerminationPredicate) + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt index a53dec3975..3c131575f4 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt @@ -20,10 +20,17 @@ import kotlin.reflect.KProperty * Context for managing variables in a simulation. */ class VariablesContext { - /** - * Map of variable references. - */ - val references: MutableMap = mutableMapOf() + + /** Map of default variable values. */ + val defaults: MutableMap = mutableMapOf() + + /** Thread-local map of variable references. */ + val references = object : ThreadLocal>() { + override fun initialValue(): Map { + logger.debug("Initializing variable references with defaults: {}", defaults) + return defaults.toMap() + } + } /** * Map of registered variables. @@ -35,6 +42,21 @@ class VariablesContext { */ val dependentVariables: MutableMap Any> = mutableMapOf() + /** + * Adds new variable references to the current thread-local context. + * Since each simulation may run in its own thread, this ensures that each simulation + * has its own set of variable references, while still using the same variable definitions. + * + * @param newRefs Map of new variable references to add to the default/existing ones. + */ + fun addReferences(newRefs: Map) { + val currMap = references.get() + val newRefs = currMap.toMutableMap().also { m -> + m.putAll(newRefs.mapValues { it.value as Any }) + } + references.set(newRefs) + } + /** * Registers a variable provider. * @@ -80,7 +102,7 @@ class VariablesContext { * @param T The type of the variable value. * @param source The function that provides the variable value. */ - inner class DependentRef(private val source: () -> T) : ReadWriteProperty { + class DependentRef(private val source: () -> T) : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): T = source() override fun setValue(thisRef: Any?, property: KProperty<*>, value: T): Unit = @@ -107,7 +129,7 @@ class VariablesContext { } logger.debug("Registering variable: {}", prop.name) variables[prop.name] = source - references[prop.name] = source.default + defaults[prop.name] = source.default return Ref() } } @@ -119,11 +141,11 @@ class VariablesContext { */ inner class Ref : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): T { - check(references.contains(property.name)) { + check(references.get().contains(property.name)) { "Variable ${property.name} has no defined value" } @Suppress("UNCHECKED_CAST") - return references[property.name] as T + return references.get()[property.name] as T } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T): Unit = diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt index e7c4c9cb76..69caebe692 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt @@ -9,10 +9,10 @@ package it.unibo.alchemist.boundary.dsl.util -import it.unibo.alchemist.boundary.dsl.SingleUseDslLoader +import it.unibo.alchemist.boundary.dsl.DSLLoader import org.slf4j.Logger import org.slf4j.LoggerFactory internal object LoadingSystemLogger { - val logger: Logger = LoggerFactory.getLogger(SingleUseDslLoader::class.java) + val logger: Logger = LoggerFactory.getLogger(DSLLoader::class.java) } diff --git a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java index 2a6cc3a6b4..9f5ecfe605 100644 --- a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java +++ b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java @@ -17,7 +17,7 @@ /** * Generic node for testing purposes. */ -@BuildDsl +@BuildDsl(scope = "DEPLOYMENT_CONTEXT") public final class TestNode extends GenericNode { @Serial diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 29c1c00a36..b18aa158c9 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -17,9 +17,11 @@ import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.boundary.dsl.generated.RectangleFilter import it.unibo.alchemist.boundary.dsl.generated.circle +import it.unibo.alchemist.boundary.dsl.generated.globalTestReaction import it.unibo.alchemist.boundary.dsl.generated.grid import it.unibo.alchemist.boundary.dsl.generated.moleculeReader import it.unibo.alchemist.boundary.dsl.generated.point +import it.unibo.alchemist.boundary.dsl.generated.polygon import it.unibo.alchemist.boundary.dsl.generated.testNode import it.unibo.alchemist.boundary.dsl.generated.testNodeProperty import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.PROTELIS @@ -33,6 +35,7 @@ import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.actions.BrownianMove import it.unibo.alchemist.model.deployments.Circle import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point @@ -45,27 +48,28 @@ import it.unibo.alchemist.model.maps.environments.OSMEnvironment import it.unibo.alchemist.model.positionfilters.Rectangle import it.unibo.alchemist.model.positions.Euclidean2DPosition import it.unibo.alchemist.model.reactions.Event +import it.unibo.alchemist.model.terminators.AfterTime import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.timedistributions.DiracComb import it.unibo.alchemist.model.timedistributions.ExponentialTime import it.unibo.alchemist.model.timedistributions.WeibullTime -import it.unibo.alchemist.test.GlobalTestReaction +import it.unibo.alchemist.model.times.DoubleTime import org.apache.commons.math3.random.MersenneTwister object DslLoaderFunctions { fun > test01Nodes(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(5.0) deployments { deploy(point(0.0, 0.0)) - deploy(Point(envAsAny, 0.0, 1.0)) + deploy(Point(ctx.environment, 0.0, 1.0)) } } } fun > test02ManyNodes(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { simulationGenerator = MersenneTwister(10L) scenarioGenerator = MersenneTwister(20L) @@ -73,7 +77,7 @@ object DslLoaderFunctions { deployments { deploy( Circle( - envAsAny, + ctx.environment, generator, 10, 0.0, @@ -85,7 +89,7 @@ object DslLoaderFunctions { } } fun > test03Grid(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { @@ -104,7 +108,7 @@ object DslLoaderFunctions { } } fun > test05Content(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { @@ -129,14 +133,14 @@ object DslLoaderFunctions { } } fun > test06ContentFiltered(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { val hello = "hello" deploy( Grid( - envAsAny, generator, + ctx.environment, generator, -5.0, -5.0, 5.0, @@ -156,7 +160,7 @@ object DslLoaderFunctions { } fun > test07Programs(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { @@ -190,16 +194,23 @@ object DslLoaderFunctions { } } fun > test08ProtelisPrograms(): Loader { - val incarnation = PROTELIS.incarnation() + val incarnation = PROTELIS.incarnation() return simulation(incarnation) { deployments { deploy(point(1.5, 0.5)) { programs { all { timeDistribution = +JaktaTimeDistribution( - sense = WeibullTime(1.0, 1.0, generator), + sense = WeibullTime( + 1.0, + 1.0, + ctx.ctx.ctx.generator, + ), deliberate = DiracComb(0.1), - act = ExponentialTime(1.0, generator), + act = ExponentialTime( + 1.0, + ctx.ctx.ctx.generator, + ), ) program = "1 + 1" } @@ -209,26 +220,26 @@ object DslLoaderFunctions { } } fun > test09TimeDistribution(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { deploy( Grid( - envAsAny, generator, + ctx.environment, generator, -5.0, -5.0, 5.0, 5.0, 0.25, 0.25, 0.1, 0.1, ), ) { inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { molecule = "token, 0, []" - programs { - all { - timeDistribution = DiracComb(0.5) - program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" - } - all { - program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" - } + } + programs { + all { + timeDistribution = DiracComb(0.5) + program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" + } + all { + program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" } } } @@ -238,8 +249,10 @@ object DslLoaderFunctions { fun > test10Environment(): Loader { val incarnation = SAPERE.incarnation() val env = OSMEnvironment(incarnation, "vcm.pbf", false) - return simulation(incarnation, env) { - addTerminator(StableForSteps(5, 100)) + return simulation(incarnation, { env }) { + terminators { + +StableForSteps(5, 100) + } deployments { val gps = FromGPSTrace( 7, @@ -250,7 +263,7 @@ object DslLoaderFunctions { deploy(gps) { programs { all { - timeDistribution("0.1") + timeDistribution("15") reaction = Event(node, timeDistribution) addAction { ReproduceGPSTrace( @@ -269,9 +282,11 @@ object DslLoaderFunctions { } } fun > test11monitors(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { - addMonitor(SimpleMonitor()) + monitors { + +SimpleMonitor() + } } } fun > test12Layers(): Loader { @@ -307,16 +322,13 @@ object DslLoaderFunctions { fun > test13GlobalReaction(): Loader { val incarnation = PROTELIS.incarnation() return simulation(incarnation) { - program( - GlobalTestReaction( - DiracComb(1.0), - environment, - ), - ) + programs { + +globalTestReaction(DiracComb(1.0)) + } } } fun > test14Exporters(): Loader { - val incarnation = PROTELIS.incarnation() + val incarnation = PROTELIS.incarnation() return simulation(incarnation) { exporter { type = CSVExporter( @@ -336,7 +348,7 @@ object DslLoaderFunctions { } } fun > test15Variables(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) @@ -344,16 +356,17 @@ object DslLoaderFunctions { val mSize by variable { -size } val sourceStart by variable { mSize / 10.0 } val sourceSize by variable { size / 5.0 } - + terminators { +AfterTime(DoubleTime(1.0)) } networkModel = ConnectWithinDistance(0.5) deployments { deploy( Grid( - environment, generator, + ctx.environment, generator, mSize, mSize, size, size, 0.25, 0.25, 0.1, 0.1, ), ) { + println("using rate $rate and size $size") inside(Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { molecule = "token, 0, []" } @@ -372,14 +385,14 @@ object DslLoaderFunctions { } fun > test16ProgramsFilters(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { val token = "token" deploy( Grid( - environment, generator, + ctx.environment, generator, -5.0, -5.0, 5.0, @@ -404,13 +417,11 @@ object DslLoaderFunctions { } } fun > test17CustomNodes(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() return simulation(incarnation) { deployments { deploy( - Circle( - environment, - generator, + circle( 10, 0.0, 0.0, @@ -427,7 +438,7 @@ object DslLoaderFunctions { fun > test18NodeProperties(): Loader { val incarnation = SAPERE.incarnation() val environment = Continuous2DEnvironment(incarnation) - return simulation(incarnation, environment) { + return simulation(incarnation, { environment }) { deployments { deploy( circle( @@ -442,10 +453,68 @@ object DslLoaderFunctions { // same val filter2 = Rectangle(3.0, 3.0, 2.0, 2.0) inside(filter) { - add(testNodeProperty("a")) + +testNodeProperty("a") } inside(filter2) { - add(testNodeProperty("b")) + +testNodeProperty("b") + } + } + } + } + } + } + fun > test20Actions(): Loader { + val incarnation = SAPERE.incarnation() + val env = OSMEnvironment(incarnation) + return simulation(incarnation, { env }) { + networkModel = ConnectWithinDistance(1000.0) + deployments { + val lagoon = listOf( + Pair(45.2038121, 12.2504425), + Pair(45.2207426, 12.2641754), + Pair(45.2381516, 12.2806549), + Pair(45.2570053, 12.2895813), + Pair(45.276336, 12.2957611), + Pair(45.3029049, 12.2991943), + Pair(45.3212544, 12.3046875), + Pair(45.331875, 12.3040009), + Pair(45.3453893, 12.3040009), + Pair(45.3502151, 12.3156738), + Pair(45.3622776, 12.3232269), + Pair(45.3719259, 12.3300934), + Pair(45.3830193, 12.3348999), + Pair(45.395557, 12.3445129), + Pair(45.3998964, 12.3300934), + Pair(45.4018249, 12.3136139), + Pair(45.4105023, 12.3122406), + Pair(45.4167685, 12.311554), + Pair(45.4278531, 12.3012543), + Pair(45.4408627, 12.2902679), + Pair(45.4355628, 12.2772217), + Pair(45.4206242, 12.2703552), + Pair(45.3994143, 12.2744751), + Pair(45.3738553, 12.2676086), + Pair(45.3579354, 12.2614288), + Pair(45.3429763, 12.2497559), + Pair(45.3198059, 12.2408295), + Pair(45.2975921, 12.2346497), + Pair(45.2802014, 12.2408295), + Pair(45.257972, 12.233963), + Pair(45.2038121, 12.2504425), + ) + deploy(polygon(500, lagoon)) { + programs { + all { + timeDistribution("10") + reaction = Event(node, timeDistribution) + addAction { + BrownianMove( + env, + node, + ctx.ctx.ctx.ctx.simulationGenerator, + 0.0005, + ) + } } } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt index e1711174e0..2e4dd85a15 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt @@ -25,7 +25,7 @@ class KotlinDslProviderTest { networkModel = ConnectWithinDistance(5.0) deployments { deploy(point(0.0, 0.0)) - deploy(Point(environment, 0.0, 1.0)) + deploy(point(0.0, 1.0)) } } """.trimIndent() diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt index 05e3d230b7..ab0e0abad9 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt @@ -14,8 +14,14 @@ import it.unibo.alchemist.core.Status import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.TerminationPredicate +import it.unibo.alchemist.model.Time +import it.unibo.alchemist.model.terminators.AfterTime +import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.terminators.StepCount +import it.unibo.alchemist.model.times.DoubleTime import kotlin.math.abs +import kotlin.math.max import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.fail @@ -29,31 +35,82 @@ import org.junit.jupiter.api.Assertions.fail object RuntimeComparisonHelper { /** - * Compares loaders by running both simulations for a specified number of steps - * and comparing their final states. + * Compares loaders by running both simulations and comparing their final states. + * + * @param dslLoader The DSL loader to compare + * @param yamlLoader The YAML loader to compare + * @param steps The number of steps to run before comparing + * (if null, uses targetTime or stableForSteps instead) + * @param targetTime Target time to run until (if null, uses steps or stableForSteps instead). + * Only one termination method should be provided. + * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). + * Only one termination method should be provided. + * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s) + * @param positionTolerance Maximum distance between positions to consider them matching. + * If null, calculated as max(timeTolerance * 10, 1e-6). + * For random movement tests, consider using a larger value (e.g., 1.0 or more). + * + * @note For simulations to advance time, all reactions must have explicit time distributions. + * Reactions without time distributions default to "Infinity" rate, which schedules + * them at time 0.0, preventing time from advancing. + * + * @note Step-based terminators ensure both simulations execute the same number of steps, + * but final times may differ slightly due to randomness. Time-based terminators + * ensure both simulations reach approximately the same time, but step counts may differ. + * StableForSteps terminators ensure both simulations terminate at a stable state, which + * works well for deterministic simulations (e.g., ReproduceGPSTrace) but may not work + * for random simulations (e.g., BrownianMove) if reactions execute in different orders. + * Small timing differences are expected even with time-based terminators due to thread + * scheduling and the terminator being checked after each step completes. */ - fun > compareLoaders(dslLoader: Loader, yamlLoader: Loader, steps: Long = 1000L) { + fun > compareLoaders( + dslLoader: Loader, + yamlLoader: Loader, + steps: Long? = null, + targetTime: Double? = null, + stableForSteps: Pair? = null, + timeTolerance: Double = 0.01, + positionTolerance: Double? = null, + ) { + val terminationMethods = listOfNotNull( + steps?.let { "steps" }, + targetTime?.let { "targetTime" }, + stableForSteps?.let { "stableForSteps" }, + ) + require(terminationMethods.size == 1) { + "Exactly one termination method must be provided: steps, targetTime, or stableForSteps. " + + "Provided: $terminationMethods" + } + + val effectiveSteps = steps ?: 0L + println("Running simulations for comparison...") val dslSimulation = dslLoader.getDefault() val yamlSimulation = yamlLoader.getDefault() - // Add step-based terminators to both simulations - addStepTerminator(dslSimulation, steps) - addStepTerminator(yamlSimulation, steps) - - try { - // Run simulations sequentially to avoid complexity - println("Running DSL simulation...") - runSimulationSynchronously(dslSimulation) - println("DSL simulation completed with status: ${dslSimulation.status}") + println( + "DSL simulation initial step: ${dslSimulation.step}, " + + "initial time: ${dslSimulation.time}", + ) + println( + "YAML simulation initial step: ${yamlSimulation.step}, " + + "initial time: ${yamlSimulation.time}", + ) - println("Running YAML simulation...") - runSimulationSynchronously(yamlSimulation) - println("YAML simulation completed with status: ${yamlSimulation.status}") + addTerminators(dslSimulation, yamlSimulation, steps, targetTime, stableForSteps) - // Compare final states - compareRuntimeStates(dslSimulation, yamlSimulation) + try { + runAndCompareSimulations( + dslSimulation, + yamlSimulation, + effectiveSteps, + targetTime, + stableForSteps, + steps, + timeTolerance, + positionTolerance, + ) } catch (e: Exception) { fail("Error during simulation execution: ${e.message}") } finally { @@ -67,21 +124,166 @@ object RuntimeComparisonHelper { } } + private fun hasTerminationCondition( + effectiveSteps: Long, + targetTime: Double?, + stableForSteps: Pair?, + ): Boolean = effectiveSteps > 0 || targetTime != null || stableForSteps != null + + private fun > addTerminators( + dslSimulation: Simulation, + yamlSimulation: Simulation, + steps: Long?, + targetTime: Double?, + stableForSteps: Pair?, + ) { + when { + steps != null -> { + addStepTerminator(dslSimulation, steps) + addStepTerminator(yamlSimulation, steps) + println("Added step-based terminators for $steps steps") + } + targetTime != null -> { + val time = DoubleTime(targetTime) + addTimeTerminator(dslSimulation, time) + addTimeTerminator(yamlSimulation, time) + println("Added time-based terminators for ${targetTime}s") + } + stableForSteps != null -> { + val (checkInterval, equalIntervals) = stableForSteps + addStableTerminator(dslSimulation, checkInterval, equalIntervals) + addStableTerminator(yamlSimulation, checkInterval, equalIntervals) + println( + "Added stable-for-steps terminators " + + "(checkInterval: $checkInterval, equalIntervals: $equalIntervals)", + ) + } + } + } + + private fun > runAndCompareSimulations( + dslSimulation: Simulation, + yamlSimulation: Simulation, + effectiveSteps: Long, + targetTime: Double?, + stableForSteps: Pair?, + steps: Long?, + timeTolerance: Double, + positionTolerance: Double?, + ) { + println("Running DSL simulation...") + runSimulationSynchronously(dslSimulation) + println( + "DSL simulation completed with status: ${dslSimulation.status}, " + + "step: ${dslSimulation.step}, time: ${dslSimulation.time}", + ) + + println("Running YAML simulation...") + runSimulationSynchronously(yamlSimulation) + println( + "YAML simulation completed with status: ${yamlSimulation.status}, " + + "step: ${yamlSimulation.step}, time: ${yamlSimulation.time}", + ) + + checkSimulationTimeAdvancement(dslSimulation, yamlSimulation, effectiveSteps, targetTime, stableForSteps) + + val effectivePositionTolerance = positionTolerance ?: max(timeTolerance * 10, 1e-6) + compareRuntimeStates( + dslSimulation, + yamlSimulation, + timeTolerance, + compareSteps = steps != null, + positionTolerance = effectivePositionTolerance, + ) + } + + private fun > checkSimulationTimeAdvancement( + dslSimulation: Simulation, + yamlSimulation: Simulation, + effectiveSteps: Long, + targetTime: Double?, + stableForSteps: Pair?, + ) { + val shouldHaveAdvanced = hasTerminationCondition(effectiveSteps, targetTime, stableForSteps) + if (dslSimulation.time.toDouble() == 0.0 && shouldHaveAdvanced) { + println( + "WARNING: DSL simulation time is 0.0. " + + "Ensure all reactions have explicit time distributions.", + ) + } + if (yamlSimulation.time.toDouble() == 0.0 && shouldHaveAdvanced) { + println( + "WARNING: YAML simulation time is 0.0. " + + "Ensure all reactions have explicit time distributions.", + ) + } + } + /** * Adds step-based terminator to a simulation. */ private fun > addStepTerminator(simulation: Simulation, steps: Long) { - // Add step-based terminator simulation.environment.addTerminator(StepCount(steps)) } + /** + * Adds time-based terminator to a simulation. + */ + private fun > addTimeTerminator(simulation: Simulation, targetTime: Time) { + simulation.environment.addTerminator(AfterTime(targetTime)) + } + + /** + * Adds stable-for-steps terminator to a simulation. + * Terminates when environment (positions + node contents) remains unchanged + * for checkInterval * equalIntervals steps. + */ + private fun > addStableTerminator( + simulation: Simulation, + checkInterval: Long, + equalIntervals: Long, + ) { + @Suppress("UNCHECKED_CAST") + val terminator = StableForSteps(checkInterval, equalIntervals) as + TerminationPredicate + simulation.environment.addTerminator(terminator) + } + /** * Runs a simulation synchronously (terminator will stop it). */ private fun > runSimulationSynchronously(simulation: Simulation) { - simulation.play() // Start the simulation - simulation.run() // Block until completion (terminator will stop it) - simulation.error.ifPresent { throw it } // Check for errors + println(" Starting simulation thread, initial step: ${simulation.step}, initial time: ${simulation.time}") + val simulationThread = Thread(simulation, "Simulation-${System.currentTimeMillis()}") + simulationThread.start() + + while (simulation.status == Status.INIT) { + Thread.sleep(10) + } + println(" Simulation reached status: ${simulation.status}, step: ${simulation.step}, time: ${simulation.time}") + + while (simulation.status != Status.READY && simulation.status != Status.TERMINATED) { + Thread.sleep(10) + } + println( + " Simulation status after waiting: ${simulation.status}, " + + "step: ${simulation.step}, time: ${simulation.time}", + ) + + if (simulation.status == Status.TERMINATED) { + println(" Simulation already terminated before play()") + simulation.error.ifPresent { throw it } + return + } + + println(" Calling play(), step: ${simulation.step}, time: ${simulation.time}") + simulation.play().get() + println(" After play(), status: ${simulation.status}, step: ${simulation.step}, time: ${simulation.time}") + + simulationThread.join() + println(" Thread joined, final step: ${simulation.step}, final time: ${simulation.time}") + + simulation.error.ifPresent { throw it } } /** @@ -90,6 +292,9 @@ object RuntimeComparisonHelper { private fun > compareRuntimeStates( dslSimulation: Simulation, yamlSimulation: Simulation, + timeTolerance: Double = 0.01, + compareSteps: Boolean = true, + positionTolerance: Double = 1e-6, ) { println("Comparing runtime simulation states...") @@ -97,10 +302,10 @@ object RuntimeComparisonHelper { val yamlEnv = yamlSimulation.environment // Compare simulation execution state - compareSimulationExecutionState(dslSimulation, yamlSimulation) + compareSimulationExecutionState(dslSimulation, yamlSimulation, timeTolerance, compareSteps) // Compare environment states - compareRuntimeEnvironmentStates(dslEnv, yamlEnv) + compareRuntimeEnvironmentStates(dslEnv, yamlEnv, positionTolerance) } /** @@ -109,21 +314,37 @@ object RuntimeComparisonHelper { private fun > compareSimulationExecutionState( dslSimulation: Simulation, yamlSimulation: Simulation, + timeTolerance: Double = 0.01, + compareSteps: Boolean = true, ) { println("Comparing simulation execution state...") - // Print simulation times for debugging (skip comparison due to timing variations) - println("DSL simulation time: ${dslSimulation.time}") - println("YAML simulation time: ${yamlSimulation.time}") - val timeDiff = abs(dslSimulation.time.toDouble() - yamlSimulation.time.toDouble()) - println("Time difference: ${timeDiff}s") + val dslTime = dslSimulation.time.toDouble() + val yamlTime = yamlSimulation.time.toDouble() + val timeDiff = abs(dslTime - yamlTime) - // Compare step counts - assertEquals( - yamlSimulation.step, - dslSimulation.step, - "Simulation step counts should match", - ) + println("DSL simulation time: ${dslSimulation.time}, step: ${dslSimulation.step}") + println("YAML simulation time: ${yamlSimulation.time}, step: ${yamlSimulation.step}") + println("Time difference: ${timeDiff}s (tolerance: ${timeTolerance}s)") + + if (timeDiff > timeTolerance) { + fail( + "Simulation times differ by ${timeDiff}s (tolerance: ${timeTolerance}s). " + + "DSL: ${dslTime}s, YAML: ${yamlTime}s", + ) + } + + // Compare step counts (only if using step-based terminator) + if (compareSteps) { + assertEquals( + yamlSimulation.step, + dslSimulation.step, + "Simulation step counts should match", + ) + } else { + val stepDiff = abs(yamlSimulation.step - dslSimulation.step) + println("Step difference: $stepDiff (not comparing - using time-based terminator)") + } // Compare status assertEquals( @@ -158,6 +379,7 @@ object RuntimeComparisonHelper { private fun > compareRuntimeEnvironmentStates( dslEnv: Environment, yamlEnv: Environment, + positionTolerance: Double = 1e-6, ) { println("Comparing runtime environment states...") @@ -175,7 +397,7 @@ object RuntimeComparisonHelper { ) // Compare node positions and contents - compareRuntimeNodeStates(dslEnv, yamlEnv) + compareRuntimeNodeStates(dslEnv, yamlEnv, positionTolerance) // Compare global reactions compareRuntimeGlobalReactions(dslEnv, yamlEnv) @@ -185,37 +407,131 @@ object RuntimeComparisonHelper { } /** - * Compares node states after runtime execution using position-based matching. + * Compares node states after runtime execution using position-based matching with tolerance. + * + * @param positionTolerance Maximum distance between positions to consider them matching (default: 1e-6) */ - private fun > compareRuntimeNodeStates(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing runtime node states...") + private fun > compareRuntimeNodeStates( + dslEnv: Environment, + yamlEnv: Environment, + positionTolerance: Double = 1e-6, + ) { + println("Comparing runtime node states... (position tolerance: $positionTolerance)") - // Create position-to-node maps for both environments - val dslNodesByPosition = dslEnv.nodes.associateBy { dslEnv.getPosition(it) } - val yamlNodesByPosition = yamlEnv.nodes.associateBy { yamlEnv.getPosition(it) } + val dslNodesWithPos = dslEnv.nodes.map { it to dslEnv.getPosition(it) } + val yamlNodesWithPos = yamlEnv.nodes.map { it to yamlEnv.getPosition(it) }.toMutableList() - // Get all unique positions - val allPositions = (dslNodesByPosition.keys + yamlNodesByPosition.keys).distinct() + val (matchedPairs, unmatchedDslNodes, distances) = matchNodesByPosition( + dslNodesWithPos, + yamlNodesWithPos, + positionTolerance, + ) - for (position in allPositions) { - val dslNode = dslNodesByPosition[position] - val yamlNode = yamlNodesByPosition[position] + printMatchingStatistics(distances, matchedPairs, dslNodesWithPos.size) + checkUnmatchedNodes(unmatchedDslNodes, yamlNodesWithPos, distances, positionTolerance) + compareMatchedNodes(matchedPairs, dslEnv, yamlEnv, positionTolerance) + } - when { - dslNode == null && yamlNode == null -> { - // Both null, continue - } - dslNode == null -> { - fail("DSL simulation missing node at position $position") - } - yamlNode == null -> { - fail("YAML simulation missing node at position $position") - } - else -> { - // Both nodes exist, compare their contents - compareNodeContentsAtPosition(dslNode, yamlNode, position) + private fun > matchNodesByPosition( + dslNodesWithPos: List, P>>, + yamlNodesWithPos: MutableList, P>>, + positionTolerance: Double, + ): Triple, Node>>, List, P>>, List> { + val matchedPairs = mutableListOf, Node>>() + val unmatchedDslNodes = mutableListOf, P>>() + val distances = mutableListOf() + + for ((dslNode, dslPos) in dslNodesWithPos) { + val closest = yamlNodesWithPos.minByOrNull { (_, yamlPos) -> + dslPos.distanceTo(yamlPos) + } + if (closest != null) { + val (yamlNode, yamlPos) = closest + val distance = dslPos.distanceTo(yamlPos) + distances.add(distance) + if (distance <= positionTolerance) { + matchedPairs.add(dslNode to yamlNode) + yamlNodesWithPos.remove(closest) + } else { + unmatchedDslNodes.add(dslNode to dslPos) } + } else { + unmatchedDslNodes.add(dslNode to dslPos) + } + } + + return Triple(matchedPairs, unmatchedDslNodes, distances) + } + + private fun printMatchingStatistics( + distances: List, + matchedPairs: List, Node>>, + totalNodes: Int, + ) { + if (distances.isNotEmpty()) { + val minDistance = distances.minOrNull() ?: Double.MAX_VALUE + val maxDistance = distances.maxOrNull() ?: 0.0 + val avgDistance = distances.average() + println( + "Position matching statistics: min=$minDistance, max=$maxDistance, " + + "avg=$avgDistance, matched=${matchedPairs.size}/$totalNodes", + ) + } + } + + private fun > checkUnmatchedNodes( + unmatchedDslNodes: List, P>>, + yamlNodesWithPos: List, P>>, + distances: List, + positionTolerance: Double, + ) { + if (unmatchedDslNodes.isNotEmpty()) { + val minDistance = distances.minOrNull() ?: Double.MAX_VALUE + val maxDistance = distances.maxOrNull() ?: 0.0 + val avgDistance = distances.average() + val positions = unmatchedDslNodes.take(10).joinToString(", ") { (_, pos) -> pos.toString() } + val moreInfo = if (unmatchedDslNodes.size > 10) { + " ... and ${unmatchedDslNodes.size - 10} more" + } else { + "" + } + fail( + "DSL simulation has ${unmatchedDslNodes.size} unmatched nodes " + + "(tolerance: $positionTolerance). Distance stats: min=$minDistance, " + + "max=$maxDistance, avg=$avgDistance. First 10 positions: $positions$moreInfo", + ) + } + if (yamlNodesWithPos.isNotEmpty()) { + val positions = yamlNodesWithPos.take(10).joinToString(", ") { (_, pos) -> pos.toString() } + val moreInfo = if (yamlNodesWithPos.size > 10) { + " ... and ${yamlNodesWithPos.size - 10} more" + } else { + "" + } + fail( + "YAML simulation has ${yamlNodesWithPos.size} unmatched nodes " + + "at positions: $positions$moreInfo", + ) + } + } + + private fun > compareMatchedNodes( + matchedPairs: List, Node>>, + dslEnv: Environment, + yamlEnv: Environment, + positionTolerance: Double, + ) { + for ((dslNode, yamlNode) in matchedPairs) { + val dslPos = dslEnv.getPosition(dslNode) + val yamlPos = yamlEnv.getPosition(yamlNode) + val distance = dslPos.distanceTo(yamlPos) + if (distance > positionTolerance) { + println( + "WARNING: Matched nodes have distance $distance " + + "(tolerance: $positionTolerance)", + ) } + compareNodeContentsAtPosition(dslNode, yamlNode, dslPos) } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt index 9cee90eafd..52b709b43b 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt @@ -85,7 +85,11 @@ class SimulationsComparisons { @Test fun > test16() { - { DslLoaderFunctions.test16ProgramsFilters() }.shouldEqual("dsl/yml/16-programsfilters.yml") + { DslLoaderFunctions.test16ProgramsFilters() } + .shouldEqual( + "dsl/yml/16-programsfilters.yml", + targetTime = 10.0, + ) } @Test @@ -97,4 +101,12 @@ class SimulationsComparisons { fun > test18() { { DslLoaderFunctions.test18NodeProperties() }.shouldEqual("dsl/yml/18-properties.yml") } + + @Test + fun > test20() { + { DslLoaderFunctions.test20Actions() }.shouldEqual( + "dsl/yml/20-move.yml", + targetTime = 10.0, + ) + } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt index d32dfabed0..94f6499f04 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt @@ -26,12 +26,21 @@ object TestComparators { * @param yamlResource The YAML resource path to compare against. * @param includeRuntime Whether to include runtime behavior comparison. * @param steps The number of steps for runtime comparison (only used if includeRuntime is true). + * Exactly one of steps, targetTime, or stableForSteps must be provided. + * @param targetTime Target time to run until (only used if includeRuntime is true). + * Exactly one of steps, targetTime, or stableForSteps must be provided. + * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). + * Exactly one of steps, targetTime, or stableForSteps must be provided. + * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s). */ fun > compare( dslLoader: () -> Loader, yamlResource: String, includeRuntime: Boolean = false, - steps: Long = 1000L, + steps: Long? = null, + targetTime: Double? = null, + stableForSteps: Pair? = null, + timeTolerance: Double = 0.01, ) { val yamlLoader = LoaderFactory.loadYaml(yamlResource) @@ -41,7 +50,15 @@ object TestComparators { // Optionally perform runtime comparison if (includeRuntime) { - RuntimeComparisonHelper.compareLoaders(dslLoader(), yamlLoader, steps) + RuntimeComparisonHelper.compareLoaders( + dslLoader(), + yamlLoader, + steps = steps, + targetTime = targetTime, + stableForSteps = stableForSteps, + timeTolerance = timeTolerance, + positionTolerance = null, + ) } } @@ -52,23 +69,49 @@ object TestComparators { * @param yamlResource The YAML resource path to compare against. * @param includeRuntime Whether to include runtime behavior comparison. * @param steps The number of steps for runtime comparison (only used if includeRuntime is true). + * Exactly one of steps, targetTime, or stableForSteps must be provided. + * @param targetTime Target time to run until (only used if includeRuntime is true). + * Exactly one of steps, targetTime, or stableForSteps must be provided. + * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). + * Exactly one of steps, targetTime, or stableForSteps must be provided. + * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s). */ fun > compare( dslCode: String, yamlResource: String, includeRuntime: Boolean = false, - steps: Long = 3000L, + steps: Long? = null, + targetTime: Double? = null, + stableForSteps: Pair? = null, + timeTolerance: Double = 0.01, ) { compare({ LoaderFactory.loadDsl(dslCode) - }, yamlResource, includeRuntime, steps) + }, yamlResource, includeRuntime, steps, targetTime, stableForSteps, timeTolerance) } + /** + * Compares two loaders directly. + * + * @param dslLoader The DSL loader to compare. + * @param yamlLoader The YAML loader to compare against. + * @param includeRuntime Whether to include runtime behavior comparison. + * @param steps The number of steps for runtime comparison (only used if includeRuntime is true). + * Exactly one of steps, targetTime, or stableForSteps must be provided. + * @param targetTime Target time to run until (only used if includeRuntime is true). + * Exactly one of steps, targetTime, or stableForSteps must be provided. + * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). + * Exactly one of steps, targetTime, or stableForSteps must be provided. + * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s). + */ fun > compare( dslLoader: Loader, yamlLoader: Loader, includeRuntime: Boolean = false, - steps: Long = 1000L, + steps: Long? = null, + targetTime: Double? = null, + stableForSteps: Pair? = null, + timeTolerance: Double = 0.01, ) { // Always perform static comparison StaticComparisonHelper.compareBasicProperties(dslLoader, yamlLoader) @@ -76,11 +119,26 @@ object TestComparators { // Optionally perform runtime comparison if (includeRuntime) { - RuntimeComparisonHelper.compareLoaders(dslLoader, yamlLoader, steps) + RuntimeComparisonHelper.compareLoaders( + dslLoader, + yamlLoader, + steps = steps, + targetTime = targetTime, + stableForSteps = stableForSteps, + timeTolerance = timeTolerance, + positionTolerance = null, + ) } } } +private fun shouldUseDefaultSteps( + includeRuntime: Boolean, + steps: Long?, + targetTime: Double?, + stableForSteps: Pair?, +): Boolean = includeRuntime && steps == null && targetTime == null && stableForSteps == null + /** * Extension function for easier test writing with static comparison only. */ @@ -88,15 +146,90 @@ fun Loader.shouldEqual(yamlResource: String) { @Suppress("UNCHECKED_CAST") TestComparators.compare({ this }, yamlResource, includeRuntime = false) } -fun Loader.shouldEqual(other: Loader, includeRuntime: Boolean = true) { + +/** + * Extension function for comparing two loaders. + * + * @param other The other loader to compare against + * @param includeRuntime Whether to include runtime behavior comparison + * @param steps The number of steps for runtime comparison. + * If includeRuntime is true and no termination method is provided, defaults to 3000L. + * @param targetTime Target time to run until. + * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. + * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). + * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. + * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s) + */ +fun Loader.shouldEqual( + other: Loader, + includeRuntime: Boolean = true, + steps: Long? = null, + targetTime: Double? = null, + stableForSteps: Pair? = null, + timeTolerance: Double = 0.01, +) { + val effectiveSteps = if (shouldUseDefaultSteps(includeRuntime, steps, targetTime, stableForSteps)) { + 3000L + } else { + steps + } @Suppress("UNCHECKED_CAST") - TestComparators.compare(this, other, includeRuntime = includeRuntime) + TestComparators.compare( + this, + other, + includeRuntime, + effectiveSteps, + targetTime, + stableForSteps, + timeTolerance, + ) } /** * Extension function for comparing DSL function with YAML resource. + * + * @param yamlResource The YAML resource path to compare against + * @param includeRuntime Whether to include runtime behavior comparison + * @param steps The number of steps for runtime comparison. + * If includeRuntime is true and no termination method is provided, defaults to 3000L. + * @param targetTime Target time to run until. + * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. + * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). + * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. + * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s) + * + * @note For simulations to advance time, all reactions must have explicit time distributions. + * Reactions without time distributions default to "Infinity" rate, which schedules + * them at time 0.0, preventing time from advancing. + * + * @note Step-based terminators ensure both simulations execute the same number of steps, + * but final times may differ slightly due to randomness. Time-based terminators + * ensure both simulations reach approximately the same time, but step counts may differ. + * StableForSteps terminators ensure both simulations terminate at a stable state, which + * works well for deterministic simulations (e.g., ReproduceGPSTrace) but may not work + * for random simulations (e.g., BrownianMove) if reactions execute in different orders. */ -fun (() -> Loader).shouldEqual(yamlResource: String, includeRuntime: Boolean = true, steps: Long = 3000L) { +fun (() -> Loader).shouldEqual( + yamlResource: String, + includeRuntime: Boolean = true, + steps: Long? = null, + targetTime: Double? = null, + stableForSteps: Pair? = null, + timeTolerance: Double = 0.01, +) { + val effectiveSteps = if (shouldUseDefaultSteps(includeRuntime, steps, targetTime, stableForSteps)) { + 3000L + } else { + steps + } @Suppress("UNCHECKED_CAST") - TestComparators.compare(this, yamlResource, includeRuntime, steps) + TestComparators.compare( + this, + yamlResource, + includeRuntime, + effectiveSteps, + targetTime, + stableForSteps, + timeTolerance, + ) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt index dc87170984..778d456138 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -23,7 +23,7 @@ class TestContents { val incarnation = SAPERE.incarnation() val loader = simulation(incarnation) { deployments { - deploy(Point(envAsAny, 0.0, 0.0)) { + deploy(Point(ctx.environment, 0.0, 0.0)) { all { molecule = "test" concentration = 1.0 diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index 75fc0b8852..98e932a20c 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -24,7 +24,7 @@ class TestDeployments { val incarnation = AvailableIncarnations.SAPERE.incarnation() val loader = simulation(incarnation) { deployments { - val p = Point(envAsAny, 0.0, 0.0) + val p = Point(ctx.environment, 0.0, 0.0) deploy(p) } } @@ -37,9 +37,9 @@ class TestDeployments { val incarnation = AvailableIncarnations.SAPERE.incarnation() val loader = simulation(incarnation) { deployments { - val point = Point(envAsAny, 0.0, 0.0) + val point = Point(ctx.environment, 0.0, 0.0) deploy(point) - deploy(Point(envAsAny, 1.0, 1.0)) + deploy(Point(ctx.environment, 1.0, 1.0)) } } @@ -52,7 +52,7 @@ class TestDeployments { val loader = simulation(incarnation) { deployments { val grid = Grid( - envAsAny, + ctx.environment, generator, 1.0, 1.0, diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt index a2a3a99bd6..0b4f538ef9 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -20,27 +20,28 @@ import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.positions.Euclidean2DPosition import org.junit.jupiter.api.Test @Suppress("UNCHECKED_CAST") class TestVariables { @Test fun > testDefaultValue() { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() simulation(incarnation) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) runLater { println("Checking variable") rate.shouldBeExactly(5.0) - (this@simulation as SimulationContextImpl).variablesContext + (this as SimulationContextImpl).variablesContext .variables.containsKey("rate").shouldBeTrue() } }.getDefault() // needed to build the simulation } @Test - fun > testOverrideValue() { - val incarnation = SAPERE.incarnation() + fun > testOverrideValue() { + val incarnation = SAPERE.incarnation() val loader = simulation(incarnation) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) deployments { @@ -55,7 +56,7 @@ class TestVariables { @Suppress("NoNameShadowing") @Test fun > testDoubleDeclaration() { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() simulation(incarnation) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) println("First declaration of rate: $rate") @@ -68,7 +69,7 @@ class TestVariables { @Test fun > testDependendVariable() { - val incarnation = SAPERE.incarnation() + val incarnation = SAPERE.incarnation() val loader = simulation(incarnation) { val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) diff --git a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts index bf2fcdef57..941bd2c9ed 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts @@ -1,4 +1,6 @@ import another.location.SimpleMonitor +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation /* * Copyright (C) 2010-2025, Danilo Pianini and contributors @@ -11,5 +13,7 @@ import another.location.SimpleMonitor val incarnation = SAPERE.incarnation() simulation(incarnation) { - addMonitor(SimpleMonitor()) + monitors { + +SimpleMonitor() + } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts index 64948c4169..6bc0077881 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts @@ -1,3 +1,4 @@ + import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation diff --git a/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts index eba436e196..40adb4b227 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts @@ -16,15 +16,11 @@ simulation(incarnation) { val filter = RectangleFilter(-3.0, -3.0, 2.0, 2.0) val filter2 = RectangleFilter(3.0, 3.0, 2.0, 2.0) inside(filter) { - add(testNodeProperty("a")) + +testNodeProperty("a") } // otherwise inside(filter2) { - add(TestNodeProperty(node, - env, - incarnation, - generator, - "b")) + +testNodeProperty("b") } } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts index b1a9a57187..4a2f873b40 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts @@ -7,7 +7,7 @@ import org.apache.commons.math3.random.MersenneTwister val incarnation = SAPERE.incarnation() val environment = Continuous2DEnvironment(incarnation) -simulation(incarnation, environment) { +simulation(incarnation, { environment }) { simulationGenerator = MersenneTwister(24L) scenarioGenerator = MersenneTwister(42L) @@ -33,7 +33,7 @@ simulation(incarnation, environment) { layer = StepLayer(0.0, 0.0, 50.0, 50.0) } - addMonitor(SimpleMonitor()) + monitors { +SimpleMonitor()} exporter { type = CSVExporter( diff --git a/alchemist-loading/src/test/resources/dsl/yml/10-environment.yml b/alchemist-loading/src/test/resources/dsl/yml/10-environment.yml index 1f3644fa0e..120ac55610 100755 --- a/alchemist-loading/src/test/resources/dsl/yml/10-environment.yml +++ b/alchemist-loading/src/test/resources/dsl/yml/10-environment.yml @@ -6,7 +6,7 @@ incarnation: sapere _pools: - pool: &move - - time-distribution: 0.1 + - time-distribution: 15 type: Event actions: - type: ReproduceGPSTrace diff --git a/alchemist-loading/src/test/resources/dsl/yml/20-move.yml b/alchemist-loading/src/test/resources/dsl/yml/20-move.yml new file mode 100644 index 0000000000..fa8cb62689 --- /dev/null +++ b/alchemist-loading/src/test/resources/dsl/yml/20-move.yml @@ -0,0 +1,22 @@ +incarnation: sapere +environment: { type: OSMEnvironment } +network-model: { type: ConnectWithinDistance, parameters: [1000] } +_venice_lagoon: &lagoon + [[45.2038121, 12.2504425], [45.2207426, 12.2641754], [45.2381516, 12.2806549], + [45.2570053, 12.2895813], [45.276336, 12.2957611], [45.3029049, 12.2991943], + [45.3212544, 12.3046875], [45.331875, 12.3040009], [45.3453893, 12.3040009], + [45.3502151, 12.3156738], [45.3622776, 12.3232269], [45.3719259, 12.3300934], + [45.3830193, 12.3348999], [45.395557, 12.3445129], [45.3998964, 12.3300934], + [45.4018249, 12.3136139], [45.4105023, 12.3122406], [45.4167685, 12.311554], + [45.4278531, 12.3012543], [45.4408627, 12.2902679], [45.4355628, 12.2772217], + [45.4206242, 12.2703552], [45.3994143, 12.2744751], [45.3738553, 12.2676086], + [45.3579354, 12.2614288], [45.3429763, 12.2497559], [45.3198059, 12.2408295], + [45.2975921, 12.2346497], [45.2802014, 12.2408295], [45.257972, 12.233963], + [45.2038121, 12.2504425]] +deployments: + type: Polygon + parameters: [500, *lagoon] + programs: + - time-distribution: 10 + type: Event + actions: { type: BrownianMove, parameters: [0.0005]} \ No newline at end of file diff --git a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt index c3afe4a746..eba555d22c 100644 --- a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt +++ b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt @@ -9,6 +9,7 @@ package it.unibo.alchemist.test +import it.unibo.alchemist.boundary.dsl.BuildDsl import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Condition @@ -19,6 +20,7 @@ import it.unibo.alchemist.model.Time import it.unibo.alchemist.model.TimeDistribution import org.danilopianini.util.ListSet import org.danilopianini.util.ListSets +@BuildDsl(scope = "GLOBAL_PROGRAMS_CONTEXT") class GlobalTestReaction(override val timeDistribution: TimeDistribution, val environment: Environment) : GlobalReaction { override fun compareTo(other: Actionable): Int = tau.compareTo(other.tau) From f3825372011b43a8f4f6073c39b11f76c8b37300 Mon Sep 17 00:00:00 2001 From: marco Date: Sun, 16 Nov 2025 16:19:23 +0100 Subject: [PATCH 034/196] feat: add custom scope definition for @BuildDsl annotation --- .../dsl/processor/ConstructorParamBuilder.kt | 287 ++++++++++-------- .../boundary/dsl/processor/ContextAccessor.kt | 92 +++++- .../dsl/processor/DefaultValueAnalyzer.kt | 61 ++-- .../dsl/processor/DslBuilderProcessor.kt | 35 ++- .../dsl/processor/FunctionGenerator.kt | 67 +++- .../boundary/dsl/processor/ImportManager.kt | 8 +- .../dsl/processor/ParameterInjector.kt | 211 ++++++++++--- .../boundary/dsl/processor/ProcessorConfig.kt | 31 ++ .../dsl/processor/TypeHierarchyChecker.kt | 87 +++--- .../dsl/processor/ContextAccessorTest.kt | 83 ++++- .../dsl/processor/ParameterInjectorTest.kt | 217 ++++++++++++- .../alchemist/model/deployments/Point.java | 2 +- .../boundary/extractors/MoleculeReader.kt | 2 +- 13 files changed, 915 insertions(+), 268 deletions(-) diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 7f59803cce..328637be31 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -103,6 +103,7 @@ object ConstructorParamBuilder { InjectionType.NODE -> "node" InjectionType.REACTION -> "reaction" InjectionType.TIMEDISTRIBUTION -> "timeDistribution" + InjectionType.FILTER -> "filter" } private fun needsCast( @@ -147,6 +148,20 @@ object ConstructorParamBuilder { return constructorTypeStr != contextParamType } + /** + * Builds constructor parameter expressions for property context. + * + * @param allParameters All constructor parameters + * @param remainingParams Parameters that are not injected + * @param paramsToSkip Set of parameter indices to skip + * @param paramNames Names of remaining parameters + * @param injectionIndices Map of injection types to parameter indices + * @param injectedParamNames Map of injection types to parameter names + * @param annotationValues Annotation values from BuildDsl + * @param typeParamNames Type parameter names + * @param injectedParamTypes Map of injection types to parameter types + * @return List of constructor parameter expressions + */ fun buildConstructorParamsForPropertyContext( allParameters: List, remainingParams: List, @@ -172,6 +187,20 @@ object ConstructorParamBuilder { contextParamName = "ctx", ) + /** + * Converts constructor parameters to property context accessors. + * + * @param injectionIndices Map of injection types to parameter indices + * @param allParameters All constructor parameters + * @param remainingParams Parameters that are not injected + * @param paramsToSkip Set of parameter indices to skip + * @param paramNames Names of remaining parameters + * @param injectedParamNames Map of injection types to parameter names + * @param annotationValues Annotation values from BuildDsl + * @param typeParamNames Type parameter names + * @param injectedParamTypes Map of injection types to parameter types + * @return List of constructor parameter expressions using property context accessors + */ fun convertToPropertyContextAccessors( injectionIndices: Map, allParameters: List, @@ -215,128 +244,146 @@ object ConstructorParamBuilder { var remainingIndex = 0 allParameters.forEachIndexed { index, param -> - when { - isInjectionIndex( - InjectionType.ENVIRONMENT, - index, - injectionIndices, - annotationValues, - "injectEnvironment", - ) -> { - constructorParams.add( - buildInjectedParam( - InjectionType.ENVIRONMENT, - param, - hasContextParams, - contextType, - contextParamName, - injectedParamNames, - injectedParamTypes, - typeParamNames, - ), - ) - } - isInjectionIndex( - InjectionType.GENERATOR, - index, - injectionIndices, - annotationValues, - "injectGenerator", - ) -> { - constructorParams.add( - buildInjectedParam( - InjectionType.GENERATOR, - param, - hasContextParams, - contextType, - contextParamName, - injectedParamNames, - injectedParamTypes, - typeParamNames, - ), - ) - } - isInjectionIndex( - InjectionType.INCARNATION, - index, - injectionIndices, - annotationValues, - "injectIncarnation", - ) -> { - constructorParams.add( - buildInjectedParam( - InjectionType.INCARNATION, - param, - hasContextParams, - contextType, - contextParamName, - injectedParamNames, - injectedParamTypes, - typeParamNames, - ), - ) - } - isInjectionIndex(InjectionType.NODE, index, injectionIndices, annotationValues, "injectNode") -> { - constructorParams.add( - buildInjectedParam( - InjectionType.NODE, - param, - hasContextParams, - contextType, - contextParamName, - injectedParamNames, - injectedParamTypes, - typeParamNames, - ), - ) - } - isInjectionIndex( - InjectionType.REACTION, - index, - injectionIndices, - annotationValues, - "injectReaction", - ) -> { - constructorParams.add( - buildInjectedParam( - InjectionType.REACTION, - param, - hasContextParams, - contextType, - contextParamName, - injectedParamNames, - injectedParamTypes, - typeParamNames, - ), - ) - } - injectionIndices.containsKey(InjectionType.TIMEDISTRIBUTION) && - index == injectionIndices[InjectionType.TIMEDISTRIBUTION] -> { - constructorParams.add( - buildInjectedParam( - InjectionType.TIMEDISTRIBUTION, - param, - hasContextParams, - contextType, - contextParamName, - injectedParamNames, - injectedParamTypes, - typeParamNames, - ), - ) - } - !paramsToSkip.contains(index) -> { - val paramName = paramNames[remainingIndex] - val remainingParam = remainingParams[remainingIndex] - val paramValue = if (remainingParam.isVararg) "*$paramName" else paramName - constructorParams.add(paramValue) - remainingIndex++ - } - else -> { - constructorParams.add("null") - } + val paramExpr = buildParamExpression( + index, + param, + remainingIndex, + remainingParams, + paramsToSkip, + paramNames, + injectionIndices, + injectedParamNames, + injectedParamTypes, + annotationValues, + typeParamNames, + hasContextParams, + contextType, + contextParamName, + ) + constructorParams.add(paramExpr.first) + if (paramExpr.second) { + remainingIndex++ } } return constructorParams } + + private fun buildParamExpression( + index: Int, + param: KSValueParameter, + remainingIndex: Int, + remainingParams: List, + paramsToSkip: Set, + paramNames: List, + injectionIndices: Map, + injectedParamNames: Map, + injectedParamTypes: Map, + annotationValues: Map, + typeParamNames: List, + hasContextParams: Boolean, + contextType: ContextType, + contextParamName: String, + ): Pair { + val injectionType = findInjectionType(index, injectionIndices, annotationValues, paramsToSkip) + if (injectionType != null) { + return buildInjectedParamExpression( + injectionType, + param, + hasContextParams, + contextType, + contextParamName, + injectedParamNames, + injectedParamTypes, + typeParamNames, + ) + } + + return buildRegularParamExpression( + index, + remainingIndex, + remainingParams, + paramsToSkip, + paramNames, + ) + } + + private fun buildInjectedParamExpression( + injectionType: InjectionType, + param: KSValueParameter, + hasContextParams: Boolean, + contextType: ContextType, + contextParamName: String, + injectedParamNames: Map, + injectedParamTypes: Map, + typeParamNames: List, + ): Pair { + val accessor = buildInjectedParam( + injectionType, + param, + hasContextParams, + contextType, + contextParamName, + injectedParamNames, + injectedParamTypes, + typeParamNames, + ) + return Pair(accessor, false) + } + + private fun buildRegularParamExpression( + index: Int, + remainingIndex: Int, + remainingParams: List, + paramsToSkip: Set, + paramNames: List, + ): Pair { + if (!paramsToSkip.contains(index)) { + val paramName = paramNames[remainingIndex] + val remainingParam = remainingParams[remainingIndex] + val paramValue = if (remainingParam.isVararg) "*$paramName" else paramName + return Pair(paramValue, true) + } + return Pair("null", false) + } + + private fun findInjectionType( + index: Int, + injectionIndices: Map, + annotationValues: Map, + paramsToSkip: Set, + ): InjectionType? { + val injectionTypes = listOf( + Triple(InjectionType.ENVIRONMENT, "injectEnvironment", true), + Triple(InjectionType.GENERATOR, "injectGenerator", true), + Triple(InjectionType.INCARNATION, "injectIncarnation", true), + Triple(InjectionType.NODE, "injectNode", true), + Triple(InjectionType.REACTION, "injectReaction", true), + Triple(InjectionType.TIMEDISTRIBUTION, "", false), + Triple(InjectionType.FILTER, "", false), + ) + + return findInjectionTypeFromList(index, injectionIndices, annotationValues, paramsToSkip, injectionTypes) + } + + private fun findInjectionTypeFromList( + index: Int, + injectionIndices: Map, + annotationValues: Map, + paramsToSkip: Set, + injectionTypes: List>, + ): InjectionType? { + for ((type, annotationKey, checkAnnotation) in injectionTypes) { + val found = if (checkAnnotation) { + isInjectionIndex(type, index, injectionIndices, annotationValues, annotationKey) + } else { + injectionIndices.containsKey(type) && + index == injectionIndices[type] && + paramsToSkip.contains(index) + } + if (found) { + return type + } + } + return null + } } diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt index afd5e3cc23..e2de57ee99 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt @@ -7,15 +7,20 @@ object ContextAccessor { /** * Gets the accessor path for an injected parameter based on the context type. * - * @param injectionType The type of injection (ENVIRONMENT, GENERATOR, INCARNATION, NODE, REACTION, TIMEDISTRIBUTION) - * @param contextType The context type (SIMULATION, DEPLOYMENT, PROGRAM, PROPERTY) + * @param injectionType The type of injection + * @param contextType The context type * @param contextParamName The name of the context parameter (default: "ctx") * @return The accessor path string */ fun getAccessor(injectionType: InjectionType, contextType: ContextType, contextParamName: String = "ctx"): String = when (contextType) { ContextType.SIMULATION -> getSimulationAccessor(injectionType, contextParamName) - ContextType.DEPLOYMENT -> getDeploymentAccessor(injectionType, contextParamName) + ContextType.EXPORTER_CONTEXT -> getExporterContextAccessor(injectionType, contextParamName) + ContextType.GLOBAL_PROGRAMS_CONTEXT -> getGlobalProgramsContextAccessor(injectionType, contextParamName) + ContextType.OUTPUT_MONITORS_CONTEXT -> getOutputMonitorsContextAccessor(injectionType, contextParamName) + ContextType.TERMINATORS_CONTEXT -> getTerminatorsContextAccessor(injectionType, contextParamName) + ContextType.DEPLOYMENT -> getDeploymentsContextAccessor(injectionType, contextParamName) + ContextType.DEPLOYMENT_CONTEXT -> getDeploymentContextAccessor(injectionType, contextParamName) ContextType.PROGRAM -> getProgramAccessor(injectionType, contextParamName) ContextType.PROPERTY -> getPropertyAccessor(injectionType, contextParamName) } @@ -30,11 +35,68 @@ object ContextAccessor { InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( "TIMEDISTRIBUTION is not available in SimulationContext", ) + InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in SimulationContext") } - private fun getDeploymentAccessor(injectionType: InjectionType, contextParamName: String): String = + private fun getExporterContextAccessor(injectionType: InjectionType, contextParamName: String): String = when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.env" + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.environment" + InjectionType.GENERATOR -> "$contextParamName.ctx.scenarioGenerator" + InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" + InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in ExporterContext") + InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in ExporterContext") + InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( + "TIMEDISTRIBUTION is not available in ExporterContext", + ) + InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in ExporterContext") + } + + private fun getGlobalProgramsContextAccessor(injectionType: InjectionType, contextParamName: String): String = + when (injectionType) { + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.environment" + InjectionType.GENERATOR -> "$contextParamName.ctx.scenarioGenerator" + InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" + InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in GlobalProgramsContext") + InjectionType.REACTION -> throw IllegalArgumentException( + "REACTION is not available in GlobalProgramsContext", + ) + InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( + "TIMEDISTRIBUTION is not available in GlobalProgramsContext", + ) + InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in GlobalProgramsContext") + } + + private fun getOutputMonitorsContextAccessor(injectionType: InjectionType, contextParamName: String): String = + when (injectionType) { + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.environment" + InjectionType.GENERATOR -> "$contextParamName.ctx.scenarioGenerator" + InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" + InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in OutputMonitorsContext") + InjectionType.REACTION -> throw IllegalArgumentException( + "REACTION is not available in OutputMonitorsContext", + ) + InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( + "TIMEDISTRIBUTION is not available in OutputMonitorsContext", + ) + InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in OutputMonitorsContext") + } + + private fun getTerminatorsContextAccessor(injectionType: InjectionType, contextParamName: String): String = + when (injectionType) { + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.environment" + InjectionType.GENERATOR -> "$contextParamName.ctx.scenarioGenerator" + InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" + InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in TerminatorsContext") + InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in TerminatorsContext") + InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( + "TIMEDISTRIBUTION is not available in TerminatorsContext", + ) + InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in TerminatorsContext") + } + + private fun getDeploymentsContextAccessor(injectionType: InjectionType, contextParamName: String): String = + when (injectionType) { + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.environment" InjectionType.GENERATOR -> "$contextParamName.generator" InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in DeploymentsContext") @@ -42,21 +104,36 @@ object ContextAccessor { InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( "TIMEDISTRIBUTION is not available in DeploymentsContext", ) + InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in DeploymentsContext") + } + + private fun getDeploymentContextAccessor(injectionType: InjectionType, contextParamName: String): String = + when (injectionType) { + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.environment" + InjectionType.GENERATOR -> "$contextParamName.ctx.generator" + InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.incarnation" + InjectionType.FILTER -> "$contextParamName.filter" + InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in DeploymentContext") + InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in DeploymentContext") + InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( + "TIMEDISTRIBUTION is not available in DeploymentContext", + ) } private fun getProgramAccessor(injectionType: InjectionType, contextParamName: String): String = when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.ctx.env" + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.ctx.ctx.environment" InjectionType.GENERATOR -> "$contextParamName.ctx.ctx.ctx.generator" InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.ctx.ctx.incarnation" InjectionType.NODE -> "$contextParamName.node" InjectionType.REACTION -> "$contextParamName.reaction" InjectionType.TIMEDISTRIBUTION -> "$contextParamName.timeDistribution!!" + InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in ProgramContext") } private fun getPropertyAccessor(injectionType: InjectionType, contextParamName: String): String = when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.ctx.env" + InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.ctx.ctx.environment" InjectionType.GENERATOR -> "$contextParamName.ctx.ctx.ctx.generator" InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.ctx.ctx.incarnation" InjectionType.NODE -> "$contextParamName.node" @@ -64,5 +141,6 @@ object ContextAccessor { InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( "TIMEDISTRIBUTION is not available in PropertyContext", ) + InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in PropertyContext") } } diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt index 30dce50d9b..dce5f9ca01 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt @@ -139,57 +139,80 @@ object DefaultValueAnalyzer { val extractionData = prepareExtractionData(param) ?: return null val defaultValue = extractBalancedExpression(extractionData.sourceCode, extractionData.startIndex) val trimmed = defaultValue?.trim()?.takeIf { it.isNotEmpty() && !it.contains("\n") } - val result = if (trimmed == null && param.hasDefault) { - val paramName = param.name?.asString() ?: return null - tryExtractSimpleDefault(extractionData.sourceCode, paramName) - } else { - trimmed - } + val result = getDefaultValueResult(trimmed, param, extractionData.sourceCode) return result?.let { qualifyMathIdentifiers(it) } } + private fun getDefaultValueResult(trimmed: String?, param: KSValueParameter, sourceCode: String): String? { + if (trimmed != null) { + return trimmed + } + return extractDefaultValueFromParam(param, sourceCode) + } + + private fun extractDefaultValueFromParam(param: KSValueParameter, sourceCode: String): String? { + if (!param.hasDefault) { + return null + } + val paramName = param.name?.asString() + return paramName?.let { tryExtractSimpleDefault(sourceCode, it) } + } + private fun qualifyMathIdentifiers(defaultValue: String): String { val replacements = mutableListOf>() + replacements.addAll(findConstantReplacements(defaultValue)) + replacements.addAll(findFunctionReplacements(defaultValue)) + + if (replacements.isEmpty()) { + return defaultValue + } + return applyReplacements(defaultValue, replacements) + } + + private fun findConstantReplacements(defaultValue: String): List> { + val replacements = mutableListOf>() for (constant in MATH_CONSTANTS) { val pattern = Regex("""\b$constant\b""") val qualifiedPattern = Regex("""\w+\.$constant\b""") if (pattern.containsMatchIn(defaultValue) && !qualifiedPattern.containsMatchIn(defaultValue)) { pattern.findAll(defaultValue).forEach { match -> - val before = defaultValue.substring(0, match.range.first) - val isQualified = before.endsWith(".") || before.endsWith("::") - if (!isQualified) { + if (!isQualifiedBefore(defaultValue, match.range.first)) { replacements.add(match.range to "kotlin.math.${match.value}") } } } } + return replacements + } + private fun findFunctionReplacements(defaultValue: String): List> { + val replacements = mutableListOf>() for (function in MATH_FUNCTIONS) { val pattern = Regex("""\b$function\s*\(""") val qualifiedPattern = Regex("""\w+\.$function\s*\(""") if (pattern.containsMatchIn(defaultValue) && !qualifiedPattern.containsMatchIn(defaultValue)) { pattern.findAll(defaultValue).forEach { match -> - val before = defaultValue.substring(0, match.range.first) - val isQualified = before.endsWith(".") || before.endsWith("::") - if (!isQualified) { + if (!isQualifiedBefore(defaultValue, match.range.first)) { replacements.add(match.range to "kotlin.math.${match.value}") } } } } + return replacements + } - if (replacements.isEmpty()) { - return defaultValue - } - - replacements.sortByDescending { it.first.first } + private fun isQualifiedBefore(defaultValue: String, index: Int): Boolean { + val before = defaultValue.substring(0, index) + return before.endsWith(".") || before.endsWith("::") + } + private fun applyReplacements(defaultValue: String, replacements: List>): String { + val sortedReplacements = replacements.sortedByDescending { it.first.first } var result = defaultValue - for ((range, replacement) in replacements) { + for ((range, replacement) in sortedReplacements) { result = result.replaceRange(range, replacement) } - return result } diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 5ccd3c0835..f4cff5877a 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -53,6 +53,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val InjectionType.NODE -> annotationValues["injectNode"] as? Boolean ?: true InjectionType.REACTION -> annotationValues["injectReaction"] as? Boolean ?: true InjectionType.TIMEDISTRIBUTION -> true + InjectionType.FILTER -> true } private fun processClass(classDecl: KSClassDeclaration) { @@ -71,6 +72,10 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val .mapNotNull { arg -> arg.name?.asString()?.let { it to arg.value } } .toMap() + logger.info("DslBuilderProcessor: Annotation values: $annotationValues") + val manualScope = annotationValues["scope"] as? String + logger.info("DslBuilderProcessor: Manual scope from annotation: '$manualScope'") + val functionName = (annotationValues["functionName"] as? String)?.takeIf { it.isNotEmpty() } ?: classDecl.simpleName.asString().replaceFirstChar { it.lowercaseChar() } @@ -90,8 +95,8 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val val injectionIndices = ParameterInjector.findInjectionIndices(parameters) logger.info("DslBuilderProcessor: Injection indices: $injectionIndices") val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - logger.info("DslBuilderProcessor: Context type: $contextType") - val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues) + logger.info("DslBuilderProcessor: Determined context type: $contextType (manual scope was: '$manualScope')") + val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues, contextType) val remainingParams = parameters.filterIndexed { index, _ -> !paramsToSkip.contains(index) } val containingFile = classDecl.containingFile @@ -232,7 +237,20 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val when (contextType) { ContextType.SIMULATION -> writer.println("import ${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}") + ContextType.EXPORTER_CONTEXT -> writer.println("import ${ProcessorConfig.ContextTypes.EXPORTER_CONTEXT}") + ContextType.GLOBAL_PROGRAMS_CONTEXT -> writer.println( + "import ${ProcessorConfig.ContextTypes.GLOBAL_PROGRAMS_CONTEXT}", + ) + ContextType.OUTPUT_MONITORS_CONTEXT -> writer.println( + "import ${ProcessorConfig.ContextTypes.OUTPUT_MONITORS_CONTEXT}", + ) + ContextType.TERMINATORS_CONTEXT -> writer.println( + "import ${ProcessorConfig.ContextTypes.TERMINATORS_CONTEXT}", + ) ContextType.DEPLOYMENT -> writer.println("import ${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}") + ContextType.DEPLOYMENT_CONTEXT -> writer.println( + "import ${ProcessorConfig.ContextTypes.DEPLOYMENT_CONTEXT}", + ) ContextType.PROGRAM -> { writer.println("import ${ProcessorConfig.ContextTypes.PROGRAM_CONTEXT}") writer.println("import ${ProcessorConfig.ContextTypes.PROPERTIES_CONTEXT}") @@ -297,6 +315,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val InjectionType.NODE -> "node" InjectionType.REACTION -> "reaction" InjectionType.TIMEDISTRIBUTION -> "td" + InjectionType.FILTER -> "filter" } private fun updateTypeParamsForInjected( @@ -461,9 +480,9 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val writer: PrintWriter, finalTypeParamBounds: List, paramTypes: List, - defaultValues: List, - classDecl: KSClassDeclaration, - needsMapEnvironment: Boolean, + @Suppress("UNUSED_PARAMETER") defaultValues: List, + @Suppress("UNUSED_PARAMETER") classDecl: KSClassDeclaration, + @Suppress("UNUSED_PARAMETER") needsMapEnvironment: Boolean, injectedParamTypesMap: Map, allParameters: List, remainingParams: List, @@ -475,10 +494,10 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val typeParamNames: List, functionName: String, className: String, - injectedParams: List>, + @Suppress("UNUSED_PARAMETER") injectedParams: List>, initialTypeParamNames: List, - initialTypeParamBounds: List, - constructorParams: List, + @Suppress("UNUSED_PARAMETER") initialTypeParamBounds: List, + @Suppress("UNUSED_PARAMETER") constructorParams: List, ) { writer.println() diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt index ccbab0876e..27fb70579d 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt @@ -68,14 +68,31 @@ object FunctionGenerator { val contextTypeName = when (contextType) { ContextType.SIMULATION -> "${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}<$tWithVariance, $pWithVariance>" + ContextType.EXPORTER_CONTEXT -> + "${ProcessorConfig.ContextTypes.EXPORTER_CONTEXT}<$tWithVariance, $pWithVariance>" + ContextType.GLOBAL_PROGRAMS_CONTEXT -> + "${ProcessorConfig.ContextTypes.GLOBAL_PROGRAMS_CONTEXT}<$tWithVariance, $pWithVariance>" + ContextType.OUTPUT_MONITORS_CONTEXT -> + "${ProcessorConfig.ContextTypes.OUTPUT_MONITORS_CONTEXT}<$tWithVariance, $pWithVariance>" + ContextType.TERMINATORS_CONTEXT -> + "${ProcessorConfig.ContextTypes.TERMINATORS_CONTEXT}<$tWithVariance, $pWithVariance>" ContextType.DEPLOYMENT -> "${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}<$tWithVariance, $pWithVariance>" + ContextType.DEPLOYMENT_CONTEXT -> + "${ProcessorConfig.ContextTypes.DEPLOYMENT_CONTEXT}<$tWithVariance, $pWithVariance>" ContextType.PROGRAM -> "${ProcessorConfig.ContextTypes.PROGRAM_CONTEXT}<$tWithVariance, $pWithVariance>" ContextType.PROPERTY -> "${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}<$tWithVariance, $pWithVariance>" } return "context(ctx: $contextTypeName) " } + /** + * Extracts variance annotation (in/out) from a type parameter bound. + * + * @param paramName The name of the type parameter + * @param typeParamBounds List of type parameter bounds + * @return The variance string ("in", "out", or empty string) + */ fun extractVarianceFromBound(paramName: String, typeParamBounds: List): String { val paramIndex = typeParamBounds.indexOfFirst { it.startsWith("$paramName:") } if (paramIndex < 0) { @@ -84,26 +101,29 @@ object FunctionGenerator { val bound = typeParamBounds[paramIndex] val boundPart = bound.substringAfter(":", "").trim() + return extractVarianceFromBoundPart(paramName, boundPart) + } + + private fun extractVarianceFromBoundPart(paramName: String, boundPart: String): String { val escapedParamName = Regex.escape(paramName) val outPattern = Regex("""""") val inPattern = Regex("""""") - if (outPattern.containsMatchIn(boundPart)) { - return "out" - } - if (inPattern.containsMatchIn(boundPart)) { - return "in" - } - - if (boundPart.startsWith("out ")) { - return "out" + return when { + outPattern.containsMatchIn(boundPart) || boundPart.startsWith("out ") -> "out" + inPattern.containsMatchIn(boundPart) || boundPart.startsWith("in ") -> "in" + else -> "" } - if (boundPart.startsWith("in ")) { - return "in" - } - return "" } + /** + * Builds the function parameter list string. + * + * @param remainingParams Parameters that are not injected + * @param paramNames Names of the remaining parameters + * @param paramTypes Types of the remaining parameters + * @return The function parameter list string + */ fun buildFunctionParams( remainingParams: List, paramNames: List, @@ -125,7 +145,12 @@ object FunctionGenerator { } } - private fun buildReceiverPart(injectedParams: List>, contextType: ContextType): String = "" + private const val EMPTY_RECEIVER = "" + + private fun buildReceiverPart( + @Suppress("UNUSED_PARAMETER") injectedParams: List>, + @Suppress("UNUSED_PARAMETER") contextType: ContextType, + ): String = EMPTY_RECEIVER /** * Builds the list of constructor parameter expressions. @@ -230,6 +255,20 @@ object FunctionGenerator { typeParamBounds: MutableList, ): String = TypeArgumentProcessor.buildContextParamType(typeRef, typeParamNames, typeParamBounds) + /** + * Builds constructor parameter expressions for property context. + * + * @param allParameters All constructor parameters + * @param remainingParams Parameters that are not injected + * @param paramsToSkip Set of parameter indices to skip + * @param paramNames Names of remaining parameters + * @param injectionIndices Map of injection types to parameter indices + * @param injectedParamNames Map of injection types to parameter names + * @param annotationValues Annotation values from BuildDsl + * @param typeParamNames Type parameter names + * @param injectedParamTypes Map of injection types to parameter types + * @return List of constructor parameter expressions + */ fun buildConstructorParamsForPropertyContext( allParameters: List, remainingParams: List, diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt index fa46ab5baa..dce4cdbc00 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt @@ -21,12 +21,12 @@ object ImportManager { */ fun writeImports( writer: PrintWriter, - typeParamBounds: List, - paramTypes: List, + @Suppress("UNUSED_PARAMETER") typeParamBounds: List, + @Suppress("UNUSED_PARAMETER") paramTypes: List, defaultValues: List, classDecl: KSClassDeclaration, - needsMapEnvironment: Boolean = false, - injectedParamTypes: List = emptyList(), + @Suppress("UNUSED_PARAMETER") needsMapEnvironment: Boolean = false, + @Suppress("UNUSED_PARAMETER") injectedParamTypes: List = emptyList(), ) { val neededImports = DefaultValueAnalyzer.extractNeededImportsFromDefaults(defaultValues, classDecl) neededImports.forEach { writer.println(it) } diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index c6eaf24643..1bf7cca0bf 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -23,6 +23,9 @@ enum class InjectionType { /** Time distribution parameter injection. */ TIMEDISTRIBUTION, + + /** Position-based filter parameter injection. */ + FILTER, } /** @@ -68,6 +71,7 @@ object ParameterInjector { isReactionType(resolved, simpleName, qualifiedName) -> indices[InjectionType.REACTION] = index isTimeDistributionType(resolved, simpleName, qualifiedName) -> indices[InjectionType.TIMEDISTRIBUTION] = index + isFilterType(resolved, simpleName, qualifiedName) -> indices[InjectionType.FILTER] = index } } @@ -140,8 +144,61 @@ object ParameterInjector { qualifiedName.startsWith("${ProcessorConfig.TIME_DISTRIBUTION_TYPE}.") } + private fun isFilterType( + type: com.google.devtools.ksp.symbol.KSType, + simpleName: String, + qualifiedName: String, + ): Boolean { + val effectiveType = type.makeNotNullable() + val effectiveDeclaration = effectiveType.declaration + val effectiveQualifiedName = effectiveDeclaration.qualifiedName?.asString().orEmpty() + val effectiveSimpleName = effectiveDeclaration.simpleName.asString() + + if (effectiveSimpleName != "PositionBasedFilter" && !effectiveQualifiedName.endsWith(".PositionBasedFilter")) { + return false + } + return TypeHierarchyChecker.isAssignableTo(effectiveType, ProcessorConfig.POSITION_BASED_FILTER_TYPE) || + effectiveQualifiedName == ProcessorConfig.POSITION_BASED_FILTER_TYPE || + effectiveQualifiedName.startsWith("${ProcessorConfig.POSITION_BASED_FILTER_TYPE}.") + } + + /** + * Parses a scope string to a ContextType enum value. + * Supports both enum names and class names (e.g., "DEPLOYMENT" or "DEPLOYMENTS_CONTEXT"). + * + * @param scope The scope string + * @return The corresponding ContextType, or null if the scope is invalid or empty + */ + fun parseScope(scope: String?): ContextType? { + if (scope.isNullOrBlank()) { + return null + } + val upperScope = scope.uppercase() + + return when (upperScope) { + "SIMULATION", "SIMULATION_CONTEXT" -> ContextType.SIMULATION + "EXPORTER", "EXPORTER_CONTEXT" -> ContextType.EXPORTER_CONTEXT + "GLOBAL_PROGRAMS", "GLOBAL_PROGRAMS_CONTEXT" -> ContextType.GLOBAL_PROGRAMS_CONTEXT + "OUTPUT_MONITORS", "OUTPUT_MONITORS_CONTEXT" -> ContextType.OUTPUT_MONITORS_CONTEXT + "TERMINATORS", "TERMINATORS_CONTEXT" -> ContextType.TERMINATORS_CONTEXT + "DEPLOYMENT", "DEPLOYMENTS_CONTEXT" -> ContextType.DEPLOYMENT + "DEPLOYMENT_CONTEXT" -> ContextType.DEPLOYMENT_CONTEXT + "PROGRAM", "PROGRAM_CONTEXT" -> ContextType.PROGRAM + "PROPERTY", "PROPERTY_CONTEXT" -> ContextType.PROPERTY + else -> { + @Suppress("SwallowedException") + try { + ContextType.valueOf(upperScope) + } catch (e: IllegalArgumentException) { + null + } + } + } + } + /** * Determines the context type based on injection indices and annotation values. + * If a manual scope is provided in the annotation, it takes precedence over automatic detection. * * @param injectionIndices Map of injection types to parameter indices * @param annotationValues Annotation values from the BuildDsl annotation @@ -151,16 +208,42 @@ object ParameterInjector { injectionIndices: Map, annotationValues: Map, ): ContextType { + val manualScope = annotationValues["scope"] as? String + if (manualScope != null && manualScope.isNotBlank()) { + val parsedScope = parseScope(manualScope) + if (parsedScope != null) { + return parsedScope + } + } + + return determineContextTypeFromInjections(injectionIndices, annotationValues) + } + + private fun determineContextTypeFromInjections( + injectionIndices: Map, + annotationValues: Map, + ): ContextType = when { + injectionIndices.containsKey(InjectionType.FILTER) -> ContextType.DEPLOYMENT_CONTEXT + hasProgramContextInjections(injectionIndices, annotationValues) -> ContextType.PROGRAM + else -> determineDeploymentOrSimulationContext(injectionIndices, annotationValues) + } + + private fun hasProgramContextInjections( + injectionIndices: Map, + annotationValues: Map, + ): Boolean { val hasNode = injectionIndices.containsKey(InjectionType.NODE) && (annotationValues["injectNode"] as? Boolean ?: true) val hasReaction = injectionIndices.containsKey(InjectionType.REACTION) && (annotationValues["injectReaction"] as? Boolean ?: true) val hasTimeDistribution = injectionIndices.containsKey(InjectionType.TIMEDISTRIBUTION) + return hasNode || hasReaction || hasTimeDistribution + } - if (hasNode || hasReaction || hasTimeDistribution) { - return ContextType.PROGRAM - } - + private fun determineDeploymentOrSimulationContext( + injectionIndices: Map, + annotationValues: Map, + ): ContextType { val hasEnvironment = injectionIndices.containsKey(InjectionType.ENVIRONMENT) && (annotationValues["injectEnvironment"] as? Boolean ?: true) val hasGenerator = injectionIndices.containsKey(InjectionType.GENERATOR) && @@ -182,56 +265,85 @@ object ParameterInjector { * * @param injectionIndices Map of injection types to parameter indices * @param annotationValues Annotation values from the BuildDsl annotation + * @param contextType The context type to determine which parameters can be injected * @return Set of parameter indices to skip */ - fun getInjectionParams(injectionIndices: Map, annotationValues: Map): Set { + fun getInjectionParams( + injectionIndices: Map, + annotationValues: Map, + contextType: ContextType, + ): Set { val paramsToSkip = mutableSetOf() - addInjectionParamIfEnabled( - InjectionType.ENVIRONMENT, - "injectEnvironment", - injectionIndices, - annotationValues, - paramsToSkip, - ) + if (isInjectionTypeAvailable(InjectionType.ENVIRONMENT, contextType)) { + addInjectionParamIfEnabled( + InjectionType.ENVIRONMENT, + "injectEnvironment", + injectionIndices, + annotationValues, + paramsToSkip, + ) + } - addInjectionParamIfEnabled( - InjectionType.GENERATOR, - "injectGenerator", - injectionIndices, - annotationValues, - paramsToSkip, - ) + if (isInjectionTypeAvailable(InjectionType.GENERATOR, contextType)) { + addInjectionParamIfEnabled( + InjectionType.GENERATOR, + "injectGenerator", + injectionIndices, + annotationValues, + paramsToSkip, + ) + } - addInjectionParamIfEnabled( - InjectionType.INCARNATION, - "injectIncarnation", - injectionIndices, - annotationValues, - paramsToSkip, - ) + if (isInjectionTypeAvailable(InjectionType.INCARNATION, contextType)) { + addInjectionParamIfEnabled( + InjectionType.INCARNATION, + "injectIncarnation", + injectionIndices, + annotationValues, + paramsToSkip, + ) + } - addInjectionParamIfEnabled( - InjectionType.NODE, - "injectNode", - injectionIndices, - annotationValues, - paramsToSkip, - ) + if (isInjectionTypeAvailable(InjectionType.NODE, contextType)) { + addInjectionParamIfEnabled( + InjectionType.NODE, + "injectNode", + injectionIndices, + annotationValues, + paramsToSkip, + ) + } - addInjectionParamIfEnabled( - InjectionType.REACTION, - "injectReaction", - injectionIndices, - annotationValues, - paramsToSkip, - ) + if (isInjectionTypeAvailable(InjectionType.REACTION, contextType)) { + addInjectionParamIfEnabled( + InjectionType.REACTION, + "injectReaction", + injectionIndices, + annotationValues, + paramsToSkip, + ) + } - injectionIndices[InjectionType.TIMEDISTRIBUTION]?.let { paramsToSkip.add(it) } + if (isInjectionTypeAvailable(InjectionType.TIMEDISTRIBUTION, contextType)) { + injectionIndices[InjectionType.TIMEDISTRIBUTION]?.let { paramsToSkip.add(it) } + } + + if (isInjectionTypeAvailable(InjectionType.FILTER, contextType)) { + injectionIndices[InjectionType.FILTER]?.let { paramsToSkip.add(it) } + } return paramsToSkip } + @Suppress("SwallowedException") + private fun isInjectionTypeAvailable(injectionType: InjectionType, contextType: ContextType): Boolean = try { + ContextAccessor.getAccessor(injectionType, contextType) + true + } catch (e: IllegalArgumentException) { + false + } + private fun addInjectionParamIfEnabled( injectionType: InjectionType, annotationKey: String, @@ -254,9 +366,24 @@ enum class ContextType { /** Simulation context (only incarnation or only environment). */ SIMULATION, - /** Deployment context (environment and generator). */ + /** Exporter context (one level below SimulationContext, manually settable). */ + EXPORTER_CONTEXT, + + /** Global programs context (one level below SimulationContext, manually settable). */ + GLOBAL_PROGRAMS_CONTEXT, + + /** Output monitors context (one level below SimulationContext, manually settable). */ + OUTPUT_MONITORS_CONTEXT, + + /** Terminators context (one level below SimulationContext, manually settable). */ + TERMINATORS_CONTEXT, + + /** Deployments context (environment and generator). */ DEPLOYMENT, + /** Deployment context (singular, one level below DeploymentsContext, includes filter). */ + DEPLOYMENT_CONTEXT, + /** Program context (includes node, reaction, and time distribution). */ PROGRAM, diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt index 431e1f722c..2f0e37fe09 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt @@ -55,6 +55,11 @@ object ProcessorConfig { */ const val TIME_DISTRIBUTION_TYPE = "$MODEL_PACKAGE.TimeDistribution" + /** + * Fully qualified name for PositionBasedFilter interface. + */ + const val POSITION_BASED_FILTER_TYPE = "$MODEL_PACKAGE.PositionBasedFilter" + /** * Fully qualified name for RandomGenerator. */ @@ -74,11 +79,37 @@ object ProcessorConfig { * Context type class names. */ object ContextTypes { + /** Fully qualified name for SimulationContext. */ const val SIMULATION_CONTEXT = "$DSL_MODEL_PACKAGE.SimulationContext" + + /** Fully qualified name for ExporterContext. */ + const val EXPORTER_CONTEXT = "$DSL_MODEL_PACKAGE.ExporterContext" + + /** Fully qualified name for GlobalProgramsContext. */ + const val GLOBAL_PROGRAMS_CONTEXT = "$DSL_MODEL_PACKAGE.GlobalProgramsContext" + + /** Fully qualified name for OutputMonitorsContext. */ + const val OUTPUT_MONITORS_CONTEXT = "$DSL_MODEL_PACKAGE.OutputMonitorsContext" + + /** Fully qualified name for TerminatorsContext. */ + const val TERMINATORS_CONTEXT = "$DSL_MODEL_PACKAGE.TerminatorsContext" + + /** Fully qualified name for DeploymentsContext. */ const val DEPLOYMENTS_CONTEXT = "$DSL_MODEL_PACKAGE.DeploymentsContext" + + /** Fully qualified name for DeploymentContext. */ + const val DEPLOYMENT_CONTEXT = "$DSL_MODEL_PACKAGE.DeploymentContext" + + /** Fully qualified name for ProgramsContext. */ const val PROGRAMS_CONTEXT = "$DSL_MODEL_PACKAGE.ProgramsContext" + + /** Fully qualified name for ProgramContext. */ const val PROGRAM_CONTEXT = "$DSL_MODEL_PACKAGE.ProgramContext" + + /** Fully qualified name for PropertiesContext. */ const val PROPERTIES_CONTEXT = "$DSL_MODEL_PACKAGE.PropertiesContext" + + /** Fully qualified name for PropertyContext. */ const val PROPERTY_CONTEXT = "$DSL_MODEL_PACKAGE.PropertyContext" } diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt index 751115ab37..f0a88ec813 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt @@ -24,11 +24,7 @@ object TypeHierarchyChecker { return true } - if (declaration is KSClassDeclaration) { - return checkSuperTypes(declaration, targetQualifiedName, mutableSetOf()) - } - - return false + return declaration is KSClassDeclaration && checkSuperTypes(declaration, targetQualifiedName, mutableSetOf()) } /** @@ -38,10 +34,11 @@ object TypeHierarchyChecker { * @param targetQualifiedName The fully qualified name of the target type * @return True if the type implements or extends the target type */ + @Suppress("SwallowedException", "TooGenericExceptionCaught") fun isAssignableTo(typeRef: KSTypeReference, targetQualifiedName: String): Boolean = try { val resolved = typeRef.resolve() isAssignableTo(resolved, targetQualifiedName) - } catch (e: Exception) { + } catch (e: RuntimeException) { false } @@ -52,39 +49,46 @@ object TypeHierarchyChecker { ): Boolean { val qualifiedName = classDecl.qualifiedName?.asString() ?: return false - if (qualifiedName in visited) { - return false - } - visited.add(qualifiedName) - - if (qualifiedName == targetQualifiedName) { - return true + return when { + qualifiedName in visited -> false + qualifiedName == targetQualifiedName -> true + else -> { + visited.add(qualifiedName) + checkSuperTypesRecursive(classDecl, targetQualifiedName, visited) + } } + } + private fun checkSuperTypesRecursive( + classDecl: KSClassDeclaration, + targetQualifiedName: String, + visited: MutableSet, + ): Boolean { val superTypes = classDecl.superTypes.toList() for (superType in superTypes) { - try { - val resolved = superType.resolve() - val superDecl = resolved.declaration - - val superQualifiedName = superDecl.qualifiedName?.asString() - if (superQualifiedName == targetQualifiedName) { - return true - } - - if (superDecl is KSClassDeclaration) { - if (checkSuperTypes(superDecl, targetQualifiedName, visited)) { - return true - } - } - } catch (e: Exception) { - continue + if (checkSuperType(superType, targetQualifiedName, visited)) { + return true } } - return false } + @Suppress("SwallowedException", "TooGenericExceptionCaught") + private fun checkSuperType( + superType: KSTypeReference, + targetQualifiedName: String, + visited: MutableSet, + ): Boolean = try { + val resolved = superType.resolve() + val superDecl = resolved.declaration + + val superQualifiedName = superDecl.qualifiedName?.asString() + superQualifiedName == targetQualifiedName || + (superDecl is KSClassDeclaration && checkSuperTypes(superDecl, targetQualifiedName, visited)) + } catch (e: RuntimeException) { + false + } + /** * Checks if a type's qualified name matches any of the provided patterns. * Falls back to string matching when type hierarchy checking is not possible. @@ -97,13 +101,8 @@ object TypeHierarchyChecker { val declaration = type.declaration val qualifiedName = declaration.qualifiedName?.asString() ?: return false - if (targetQualifiedNames.contains(qualifiedName)) { - return true - } - - return targetQualifiedNames.any { targetName -> - isAssignableTo(type, targetName) - } + return targetQualifiedNames.contains(qualifiedName) || + targetQualifiedNames.any { targetName -> isAssignableTo(type, targetName) } } /** @@ -118,16 +117,8 @@ object TypeHierarchyChecker { val declaration = type.declaration val qualifiedName = declaration.qualifiedName?.asString() ?: return false - if (qualifiedName == targetQualifiedName) { - return true - } - - if (isAssignableTo(type, targetQualifiedName)) { - return true - } - - return packagePatterns.any { pattern -> - qualifiedName.startsWith(pattern) - } + return qualifiedName == targetQualifiedName || + isAssignableTo(type, targetQualifiedName) || + packagePatterns.any { pattern -> qualifiedName.startsWith(pattern) } } } diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt index 1f50b39d59..79067eac00 100644 --- a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt +++ b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt @@ -14,9 +14,73 @@ class ContextAccessorTest { assertEquals("ctx.incarnation", ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.SIMULATION)) } + @Test + fun `test exporter context accessors`() { + assertEquals( + "ctx.ctx.environment", + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.EXPORTER_CONTEXT), + ) + assertEquals( + "ctx.ctx.scenarioGenerator", + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.EXPORTER_CONTEXT), + ) + assertEquals( + "ctx.ctx.incarnation", + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.EXPORTER_CONTEXT), + ) + } + + @Test + fun `test global programs context accessors`() { + assertEquals( + "ctx.ctx.environment", + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.GLOBAL_PROGRAMS_CONTEXT), + ) + assertEquals( + "ctx.ctx.scenarioGenerator", + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.GLOBAL_PROGRAMS_CONTEXT), + ) + assertEquals( + "ctx.ctx.incarnation", + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.GLOBAL_PROGRAMS_CONTEXT), + ) + } + + @Test + fun `test output monitors context accessors`() { + assertEquals( + "ctx.ctx.environment", + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.OUTPUT_MONITORS_CONTEXT), + ) + assertEquals( + "ctx.ctx.scenarioGenerator", + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.OUTPUT_MONITORS_CONTEXT), + ) + assertEquals( + "ctx.ctx.incarnation", + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.OUTPUT_MONITORS_CONTEXT), + ) + } + + @Test + fun `test terminators context accessors`() { + assertEquals( + "ctx.ctx.environment", + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.TERMINATORS_CONTEXT), + ) + assertEquals( + "ctx.ctx.scenarioGenerator", + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.TERMINATORS_CONTEXT), + ) + assertEquals( + "ctx.ctx.incarnation", + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.TERMINATORS_CONTEXT), + ) + } + @Test fun `test deployment context accessors`() { - assertEquals("ctx.env", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT)) + assertEquals("ctx.environment", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT)) assertEquals("ctx.generator", ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.DEPLOYMENT)) assertEquals( "ctx.ctx.incarnation", @@ -24,6 +88,23 @@ class ContextAccessorTest { ) } + @Test + fun `test deployment context singular accessors`() { + assertEquals( + "ctx.ctx.environment", + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT_CONTEXT), + ) + assertEquals( + "ctx.ctx.generator", + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.DEPLOYMENT_CONTEXT), + ) + assertEquals( + "ctx.ctx.ctx.incarnation", + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.DEPLOYMENT_CONTEXT), + ) + assertEquals("ctx.filter", ContextAccessor.getAccessor(InjectionType.FILTER, ContextType.DEPLOYMENT_CONTEXT)) + } + @Test fun `test program context accessors`() { assertEquals("ctx.ctx.ctx.env", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROGRAM)) diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt index 013d725165..7b0f19f299 100644 --- a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt +++ b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt @@ -64,7 +64,7 @@ class ParameterInjectorTest { ) val annotationValues = emptyMap() - val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues) + val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues, ContextType.PROGRAM) assertEquals(setOf(0, 1, 2), paramsToSkip) } @@ -77,7 +77,11 @@ class ParameterInjectorTest { ) val annotationValues = mapOf("injectEnvironment" to false) - val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues) + val paramsToSkip = ParameterInjector.getInjectionParams( + injectionIndices, + annotationValues, + ContextType.DEPLOYMENT, + ) assertEquals(setOf(1), paramsToSkip) } @@ -89,8 +93,215 @@ class ParameterInjectorTest { ) val annotationValues = emptyMap() - val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues) + val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues, ContextType.PROGRAM) + + assertEquals(setOf(0), paramsToSkip) + } + + @Test + fun `test getInjectionParams with GlobalProgramsContext only injects available parameters`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + InjectionType.TIMEDISTRIBUTION to 1, + ) + val annotationValues = emptyMap() + + val paramsToSkip = ParameterInjector.getInjectionParams( + injectionIndices, + annotationValues, + ContextType.GLOBAL_PROGRAMS_CONTEXT, + ) assertEquals(setOf(0), paramsToSkip) } + + @Test + fun `test determineContextType with manual scope PROGRAM override`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = mapOf("scope" to "PROGRAM") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.PROGRAM, contextType) + } + + @Test + fun `test determineContextType with manual scope SIMULATION override`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + InjectionType.GENERATOR to 1, + ) + val annotationValues = mapOf("scope" to "SIMULATION") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.SIMULATION, contextType) + } + + @Test + fun `test determineContextType with manual scope DEPLOYMENT override`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = mapOf("scope" to "DEPLOYMENT") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.DEPLOYMENT, contextType) + } + + @Test + fun `test determineContextType with manual scope DEPLOYMENTS_CONTEXT override`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = mapOf("scope" to "DEPLOYMENTS_CONTEXT") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.DEPLOYMENT, contextType) + } + + @Test + fun `test determineContextType with manual scope PROPERTY override`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = mapOf("scope" to "PROPERTY") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.PROPERTY, contextType) + } + + @Test + fun `test determineContextType with filter parameter`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + InjectionType.FILTER to 1, + ) + val annotationValues = emptyMap() + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.DEPLOYMENT_CONTEXT, contextType) + } + + @Test + fun `test determineContextType with filter and manual scope override`() { + val injectionIndices = mapOf( + InjectionType.FILTER to 0, + ) + val annotationValues = mapOf("scope" to "PROGRAM") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.PROGRAM, contextType) + } + + @Test + fun `test determineContextType with manual scope EXPORTER_CONTEXT override`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = mapOf("scope" to "EXPORTER_CONTEXT") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.EXPORTER_CONTEXT, contextType) + } + + @Test + fun `test determineContextType with manual scope GLOBAL_PROGRAMS_CONTEXT override`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = mapOf("scope" to "GLOBAL_PROGRAMS_CONTEXT") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.GLOBAL_PROGRAMS_CONTEXT, contextType) + } + + @Test + fun `test determineContextType with manual scope OUTPUT_MONITORS_CONTEXT override`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = mapOf("scope" to "OUTPUT_MONITORS_CONTEXT") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.OUTPUT_MONITORS_CONTEXT, contextType) + } + + @Test + fun `test determineContextType with manual scope TERMINATORS_CONTEXT override`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = mapOf("scope" to "TERMINATORS_CONTEXT") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.TERMINATORS_CONTEXT, contextType) + } + + @Test + fun `test determineContextType with invalid scope falls back to automatic detection`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = mapOf("scope" to "INVALID_SCOPE") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.SIMULATION, contextType) + } + + @Test + fun `test determineContextType with empty scope falls back to automatic detection`() { + val injectionIndices = mapOf( + InjectionType.ENVIRONMENT to 0, + ) + val annotationValues = mapOf("scope" to "") + + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + + assertEquals(ContextType.SIMULATION, contextType) + } + + @Test + fun `test parseScope with valid values`() { + assertEquals(ContextType.PROGRAM, ParameterInjector.parseScope("PROGRAM")) + assertEquals(ContextType.SIMULATION, ParameterInjector.parseScope("SIMULATION")) + assertEquals(ContextType.SIMULATION, ParameterInjector.parseScope("SIMULATION_CONTEXT")) + assertEquals(ContextType.EXPORTER_CONTEXT, ParameterInjector.parseScope("EXPORTER")) + assertEquals(ContextType.EXPORTER_CONTEXT, ParameterInjector.parseScope("EXPORTER_CONTEXT")) + assertEquals(ContextType.GLOBAL_PROGRAMS_CONTEXT, ParameterInjector.parseScope("GLOBAL_PROGRAMS")) + assertEquals(ContextType.GLOBAL_PROGRAMS_CONTEXT, ParameterInjector.parseScope("GLOBAL_PROGRAMS_CONTEXT")) + assertEquals(ContextType.OUTPUT_MONITORS_CONTEXT, ParameterInjector.parseScope("OUTPUT_MONITORS")) + assertEquals(ContextType.OUTPUT_MONITORS_CONTEXT, ParameterInjector.parseScope("OUTPUT_MONITORS_CONTEXT")) + assertEquals(ContextType.TERMINATORS_CONTEXT, ParameterInjector.parseScope("TERMINATORS")) + assertEquals(ContextType.TERMINATORS_CONTEXT, ParameterInjector.parseScope("TERMINATORS_CONTEXT")) + assertEquals(ContextType.DEPLOYMENT, ParameterInjector.parseScope("DEPLOYMENT")) + assertEquals(ContextType.DEPLOYMENT, ParameterInjector.parseScope("DEPLOYMENTS_CONTEXT")) + assertEquals(ContextType.DEPLOYMENT_CONTEXT, ParameterInjector.parseScope("DEPLOYMENT_CONTEXT")) + assertEquals(ContextType.PROPERTY, ParameterInjector.parseScope("PROPERTY")) + assertEquals(ContextType.PROPERTY, ParameterInjector.parseScope("PROPERTY_CONTEXT")) + assertEquals(ContextType.PROGRAM, ParameterInjector.parseScope("PROGRAM_CONTEXT")) + assertEquals(ContextType.PROGRAM, ParameterInjector.parseScope("program")) + assertEquals(ContextType.SIMULATION, ParameterInjector.parseScope("simulation")) + assertEquals(ContextType.DEPLOYMENT, ParameterInjector.parseScope("deployments_context")) + assertEquals(ContextType.EXPORTER_CONTEXT, ParameterInjector.parseScope("exporter")) + } + + @Test + fun `test parseScope with invalid values`() { + assertEquals(null, ParameterInjector.parseScope("INVALID")) + assertEquals(null, ParameterInjector.parseScope("")) + assertEquals(null, ParameterInjector.parseScope(null)) + } } diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java index 2d81b080e2..2c6b885bdc 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java @@ -22,7 +22,7 @@ * * @param

position type */ -@BuildDsl +@BuildDsl(scope = "DEPLOYMENTS_CONTEXT") public final class Point

> implements Deployment

{ private final double x; diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt index a4901551b9..7ef0cc1630 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt @@ -35,7 +35,7 @@ import kotlin.math.min * aggregating data. If an empty list is passed, then the values * will be logged indipendently for each node. */ -@BuildDsl +@BuildDsl(scope = "EXPORTER_CONTEXT") class MoleculeReader @JvmOverloads constructor( From 05b541503fee41574bf1e3b2824474b6e56482fb Mon Sep 17 00:00:00 2001 From: marco Date: Sun, 16 Nov 2025 16:34:23 +0100 Subject: [PATCH 035/196] test: add test simulation config --- src/test/resources/dodgeball.alchemist.kts | 33 ++++++++++++++++++++++ src/test/resources/dodgeball.yml | 14 +++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/test/resources/dodgeball.alchemist.kts create mode 100644 src/test/resources/dodgeball.yml diff --git a/src/test/resources/dodgeball.alchemist.kts b/src/test/resources/dodgeball.alchemist.kts new file mode 100644 index 0000000000..bfac78b697 --- /dev/null +++ b/src/test/resources/dodgeball.alchemist.kts @@ -0,0 +1,33 @@ +import it.unibo.alchemist.boundary.dsl.Dsl.incarnation +import it.unibo.alchemist.boundary.dsl.Dsl.simulation + +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +import it.unibo.alchemist.boundary.swingui.monitor.impl.SwingGUI +val incarnation = SAPERE.incarnation() +simulation(incarnation) { + networkModel = ConnectWithinDistance(0.5) + monitors { +SwingGUI(environment)} + deployments{ + deploy (grid(-5.0, -5.0, 5.0, 5.0, + 0.25, 0.25, 0.1, 0.1, 0.0, 0.0)){ + inside(RectangleFilter(-0.5, -0.5, 1.0, 1.0)) { + molecule = "ball" + } + all{ molecule = "{hit, 0}"} + programs { + all{ + timeDistribution("1") + program = "{ball} {hit, N} --> {hit, N + 1} {launching}" + } + all { program = "{launching} --> +{ball}"} + } + } + } +} diff --git a/src/test/resources/dodgeball.yml b/src/test/resources/dodgeball.yml new file mode 100644 index 0000000000..503a1237c0 --- /dev/null +++ b/src/test/resources/dodgeball.yml @@ -0,0 +1,14 @@ +incarnation: sapere +network-model: { type: ConnectWithinDistance, parameters: [0.5] } +deployments: + type: Grid + parameters: [-5.0, -5.0, 5.0, 5.0, 0.25, 0.25, 0.1, 0.1, 0.0, 0.0] # A perturbed grid of devices + contents: + - molecule: "{hit, 0}" # Everywhere, no one has been hit + - in: { type: Rectangle, parameters: [-0.5, -0.5, 1, 1] } # Inside this shape... + molecule: ball # ...every node has a ball + programs: + - time-distribution: 1 # This is a frequency, time distribution type is left to the incarnation + # 'program' specs are passed down to the incarnation for being interpreted as reactions + program: "{ball} {hit, N} --> {hit, N + 1} {launching}" # If hit, count the hit + - program: "{launching} --> +{ball}" # As soon as possible, throw the ball to a neighbor \ No newline at end of file From d19e1d28faeaadc07ba7104214c072dcc2251e2b Mon Sep 17 00:00:00 2001 From: marco Date: Tue, 25 Nov 2025 17:46:13 +0100 Subject: [PATCH 036/196] style: improve formatting --- .../dsl/processor/ConstructorParamBuilder.kt | 2 +- .../boundary/dsl/processor/DslBuilderProcessor.kt | 4 ++-- .../boundary/dsl/processor/ParameterInjector.kt | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 328637be31..467a523279 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -60,7 +60,7 @@ object ConstructorParamBuilder { annotationKey: String, ): Boolean = injectionIndices.containsKey(injectionType) && index == injectionIndices[injectionType] && - (annotationValues[annotationKey] as? Boolean ?: true) + annotationValues[annotationKey] as? Boolean ?: true private fun buildInjectedParam( injectionType: InjectionType, diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index f4cff5877a..8c56c3363d 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -198,9 +198,9 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val ) val hasNode = injectionIndices.containsKey(InjectionType.NODE) && - (annotationValues["injectNode"] as? Boolean ?: true) + annotationValues["injectNode"] as? Boolean ?: true val hasReaction = injectionIndices.containsKey(InjectionType.REACTION) && - (annotationValues["injectReaction"] as? Boolean ?: true) + annotationValues["injectReaction"] as? Boolean ?: true if (hasNode && !hasReaction) { writePropertyContextFunction( diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index 1bf7cca0bf..2e21e703a7 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -233,9 +233,9 @@ object ParameterInjector { annotationValues: Map, ): Boolean { val hasNode = injectionIndices.containsKey(InjectionType.NODE) && - (annotationValues["injectNode"] as? Boolean ?: true) + annotationValues["injectNode"] as? Boolean ?: true val hasReaction = injectionIndices.containsKey(InjectionType.REACTION) && - (annotationValues["injectReaction"] as? Boolean ?: true) + annotationValues["injectReaction"] as? Boolean ?: true val hasTimeDistribution = injectionIndices.containsKey(InjectionType.TIMEDISTRIBUTION) return hasNode || hasReaction || hasTimeDistribution } @@ -245,11 +245,11 @@ object ParameterInjector { annotationValues: Map, ): ContextType { val hasEnvironment = injectionIndices.containsKey(InjectionType.ENVIRONMENT) && - (annotationValues["injectEnvironment"] as? Boolean ?: true) + annotationValues["injectEnvironment"] as? Boolean ?: true val hasGenerator = injectionIndices.containsKey(InjectionType.GENERATOR) && - (annotationValues["injectGenerator"] as? Boolean ?: true) + annotationValues["injectGenerator"] as? Boolean ?: true val hasIncarnation = injectionIndices.containsKey(InjectionType.INCARNATION) && - (annotationValues["injectIncarnation"] as? Boolean ?: true) + annotationValues["injectIncarnation"] as? Boolean ?: true val injectedCount = listOf(hasEnvironment, hasGenerator, hasIncarnation).count { it } @@ -351,7 +351,7 @@ object ParameterInjector { annotationValues: Map, paramsToSkip: MutableSet, ) { - if ((annotationValues[annotationKey] as? Boolean ?: true) && + if (annotationValues[annotationKey] as? Boolean ?: true && injectionIndices.containsKey(injectionType) ) { injectionIndices[injectionType]?.let { paramsToSkip.add(it) } From 5169700c7aa7d21dea9413c592d8b2d637485896 Mon Sep 17 00:00:00 2001 From: marco Date: Tue, 25 Nov 2025 19:50:07 +0100 Subject: [PATCH 037/196] refactor: refactor build.gradle.kts dependency --- alchemist-dsl-processor/build.gradle.kts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/alchemist-dsl-processor/build.gradle.kts b/alchemist-dsl-processor/build.gradle.kts index 6c53b57202..7d87232269 100644 --- a/alchemist-dsl-processor/build.gradle.kts +++ b/alchemist-dsl-processor/build.gradle.kts @@ -1,12 +1,13 @@ +import Libs.alchemist + plugins { id("kotlin-jvm-convention") - kotlin("jvm") } dependencies { + + api(alchemist("api")) implementation(libs.ksp.api) - api(project(":alchemist-api")) -// api(project(":alchemist-dsl-api")) testImplementation(libs.bundles.testing.compile) testRuntimeOnly(libs.bundles.testing.runtimeOnly) From 1595d294b7a00bfae257eab625424dd02a9b1532 Mon Sep 17 00:00:00 2001 From: marco Date: Tue, 25 Nov 2025 22:59:55 +0100 Subject: [PATCH 038/196] feat: add multiplatform support --- alchemist-dsl-processor/build.gradle.kts | 29 +++++++++++++------ ...ols.ksp.processing.SymbolProcessorProvider | 1 + 2 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 alchemist-dsl-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider diff --git a/alchemist-dsl-processor/build.gradle.kts b/alchemist-dsl-processor/build.gradle.kts index 7d87232269..5be2e4baa2 100644 --- a/alchemist-dsl-processor/build.gradle.kts +++ b/alchemist-dsl-processor/build.gradle.kts @@ -1,14 +1,25 @@ import Libs.alchemist plugins { - id("kotlin-jvm-convention") + id("kotlin-multiplatform-convention") } - -dependencies { - - api(alchemist("api")) - implementation(libs.ksp.api) - - testImplementation(libs.bundles.testing.compile) - testRuntimeOnly(libs.bundles.testing.runtimeOnly) +kotlin { + jvm() + sourceSets { + val jvmMain by getting { + dependencies { + api(alchemist("api")) + implementation(libs.ksp.api) + } + kotlin.srcDir("src/main/kotlin") + resources.srcDir("src/main/resources") + } + val jvmTest by getting { + dependencies { + implementation(libs.bundles.testing.compile) + runtimeOnly(libs.bundles.testing.runtimeOnly) + } + kotlin.srcDir("src/test/kotlin") + } + } } diff --git a/alchemist-dsl-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/alchemist-dsl-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider new file mode 100644 index 0000000000..a7f2e32765 --- /dev/null +++ b/alchemist-dsl-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider @@ -0,0 +1 @@ +it.unibo.alchemist.boundary.dsl.processor.DslBuilderProcessorProvider \ No newline at end of file From 3f8083a579e6dbc71cc8bafbbd04d5952b40361f Mon Sep 17 00:00:00 2001 From: marco Date: Tue, 25 Nov 2025 23:03:11 +0100 Subject: [PATCH 039/196] chore: remove useless comment --- alchemist-loading/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/alchemist-loading/build.gradle.kts b/alchemist-loading/build.gradle.kts index 5c0dee62e6..dc2a051926 100644 --- a/alchemist-loading/build.gradle.kts +++ b/alchemist-loading/build.gradle.kts @@ -46,7 +46,6 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-scripting-common") implementation("org.jetbrains.kotlin:kotlin-scripting-jvm") implementation("org.jetbrains.kotlin:kotlin-scripting-jvm-host") - // implementation(project(":")) // the script definition module runtimeOnly(libs.groovy.jsr223) runtimeOnly(kotlin("scripting-jsr223")) From 188d4c22ce7c223504e605a23139e21ab9c793b8 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 01:16:31 +0100 Subject: [PATCH 040/196] feat: change alchemist script definition --- .../boundary/dsl/scripting/AlchemistScript.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt index 1e29057b7e..92868ea5fc 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt @@ -10,9 +10,12 @@ package it.unibo.alchemist.boundary.dsl.scripting import kotlin.script.experimental.annotations.KotlinScript +import kotlin.script.experimental.api.ScriptAcceptedLocation import kotlin.script.experimental.api.ScriptCompilationConfiguration +import kotlin.script.experimental.api.acceptedLocations import kotlin.script.experimental.api.compilerOptions import kotlin.script.experimental.api.defaultImports +import kotlin.script.experimental.api.ide import kotlin.script.experimental.jvm.dependenciesFromClassContext import kotlin.script.experimental.jvm.jvm @@ -24,7 +27,7 @@ import kotlin.script.experimental.jvm.jvm fileExtension = "alchemist.kts", compilationConfiguration = AlchemistCompilationConfiguration::class, ) -interface AlchemistScript +abstract class AlchemistScript /** * Compilation configuration for Alchemist scripts. @@ -37,6 +40,7 @@ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ "it.unibo.alchemist.boundary.dsl.model.Incarnation.*", "it.unibo.alchemist.boundary.dsl.generated.*", "it.unibo.alchemist.boundary.dsl.*", + "it.unibo.alchemist.boundary.dsl.Dsl.*", "it.unibo.alchemist.model.maps.actions.*", "it.unibo.alchemist.model.maps.deployments.*", "it.unibo.alchemist.model.maps.environments.*", @@ -71,7 +75,9 @@ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ "it.unibo.alchemist.boundary.variables.*", "it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger", ) - + ide { + acceptedLocations(ScriptAcceptedLocation.Everywhere) + } jvm { dependenciesFromClassContext(AlchemistScript::class, wholeClasspath = true) compilerOptions.append("-Xcontext-parameters") From eead30d168b5665dac410d0bf37aab126ca78e15 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 01:20:42 +0100 Subject: [PATCH 041/196] chore: add dependencies versions --- alchemist-loading/build.gradle.kts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/alchemist-loading/build.gradle.kts b/alchemist-loading/build.gradle.kts index dc2a051926..7be2d27514 100644 --- a/alchemist-loading/build.gradle.kts +++ b/alchemist-loading/build.gradle.kts @@ -19,7 +19,6 @@ import Libs.incarnation */ plugins { id("kotlin-jvm-convention") - kotlin("jvm") alias(libs.plugins.ksp) } @@ -43,9 +42,9 @@ dependencies { implementation(libs.mongodb) implementation(libs.snakeyaml) - implementation("org.jetbrains.kotlin:kotlin-scripting-common") - implementation("org.jetbrains.kotlin:kotlin-scripting-jvm") - implementation("org.jetbrains.kotlin:kotlin-scripting-jvm-host") + implementation("org.jetbrains.kotlin:kotlin-scripting-common:${libs.versions.kotlin.get()}") + implementation("org.jetbrains.kotlin:kotlin-scripting-jvm:${libs.versions.kotlin.get()}") + implementation("org.jetbrains.kotlin:kotlin-scripting-jvm-host:${libs.versions.kotlin.get()}") runtimeOnly(libs.groovy.jsr223) runtimeOnly(kotlin("scripting-jsr223")) From 8828e2eb924048b1e8a041b6b16a11fcc6dc05bb Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 01:23:02 +0100 Subject: [PATCH 042/196] fix: fix processor tests --- .../dsl/processor/ContextAccessorTest.kt | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt index 79067eac00..659bee8ae0 100644 --- a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt +++ b/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.boundary.dsl.processor import org.junit.jupiter.api.Assertions.assertEquals @@ -80,7 +89,10 @@ class ContextAccessorTest { @Test fun `test deployment context accessors`() { - assertEquals("ctx.environment", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT)) + assertEquals( + "ctx.ctx.environment", + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT), + ) assertEquals("ctx.generator", ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.DEPLOYMENT)) assertEquals( "ctx.ctx.incarnation", @@ -91,7 +103,7 @@ class ContextAccessorTest { @Test fun `test deployment context singular accessors`() { assertEquals( - "ctx.ctx.environment", + "ctx.ctx.ctx.environment", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT_CONTEXT), ) assertEquals( @@ -107,10 +119,16 @@ class ContextAccessorTest { @Test fun `test program context accessors`() { - assertEquals("ctx.ctx.ctx.env", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROGRAM)) - assertEquals("ctx.ctx.ctx.generator", ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROGRAM)) assertEquals( - "ctx.ctx.ctx.ctx.incarnation", + "ctx.ctx.ctx.ctx.ctx.environment", + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROGRAM), + ) + assertEquals( + "ctx.ctx.ctx.ctx.generator", + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROGRAM), + ) + assertEquals( + "ctx.ctx.ctx.ctx.ctx.incarnation", ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.PROGRAM), ) assertEquals("ctx.node", ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROGRAM)) @@ -123,13 +141,16 @@ class ContextAccessorTest { @Test fun `test property context accessors`() { - assertEquals("ctx.ctx.ctx.env", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROPERTY)) assertEquals( - "ctx.ctx.ctx.generator", + "ctx.ctx.ctx.ctx.ctx.environment", + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROPERTY), + ) + assertEquals( + "ctx.ctx.ctx.ctx.generator", ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROPERTY), ) assertEquals( - "ctx.ctx.ctx.ctx.incarnation", + "ctx.ctx.ctx.ctx.ctx.incarnation", ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.PROPERTY), ) assertEquals("ctx.node", ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROPERTY)) @@ -138,7 +159,7 @@ class ContextAccessorTest { @Test fun `test custom context parameter name`() { assertEquals( - "customCtx.env", + "customCtx.ctx.environment", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT, "customCtx"), ) assertEquals( From fb371576c7d846d55b1396b5a96811c6baf9aa6b Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 01:26:10 +0100 Subject: [PATCH 043/196] chore: remove println --- .../it/unibo/alchemist/dsl/DslLoaderFunctions.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index b18aa158c9..e11e51d269 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -360,13 +360,17 @@ object DslLoaderFunctions { networkModel = ConnectWithinDistance(0.5) deployments { deploy( - Grid( - ctx.environment, generator, - mSize, mSize, size, size, - 0.25, 0.25, 0.1, 0.1, + grid( + mSize, + mSize, + size, + size, + 0.25, + 0.25, + 0.1, + 0.1, ), ) { - println("using rate $rate and size $size") inside(Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { molecule = "token, 0, []" } From a2621eec17992c2ec7897c911b5087b5f0e7f77c Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 01:27:58 +0100 Subject: [PATCH 044/196] style: remove redundant parenthesis --- .../src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt index 0b4f538ef9..a7fc78f1f9 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -50,7 +50,7 @@ class TestVariables { .variables.containsKey("rate").shouldBeTrue() } } - loader.getWith(mapOf(("rate" to 20.0))) + loader.getWith(mapOf("rate" to 20.0)) } @Suppress("NoNameShadowing") From 044f0cf31204e0c3cc4a528c972200a5ca5755cf Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 01:30:52 +0100 Subject: [PATCH 045/196] style: remove redundant parenthesis --- .../test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt index 180306ede1..f98e6ad0eb 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt @@ -17,7 +17,7 @@ object LayerComparisonUtils { if (uniquePositions.isNotEmpty()) { for (position in uniquePositions) { - val dslLayerValues = dslEnv.layers.map { (it.getValue(position)) } + val dslLayerValues = dslEnv.layers.map { it.getValue(position) } val yamlLayerValues = yamlEnv.layers.map { it.getValue(position) } val dslDoubleValues = dslLayerValues.map { value -> when (value) { From a484608bb898087ef00c3bdef9b108f0b4433d70 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 15:55:30 +0100 Subject: [PATCH 046/196] chore: remove not needed compiler arg --- alchemist-loading/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/alchemist-loading/build.gradle.kts b/alchemist-loading/build.gradle.kts index 7be2d27514..15c518844b 100644 --- a/alchemist-loading/build.gradle.kts +++ b/alchemist-loading/build.gradle.kts @@ -86,7 +86,6 @@ tasks.withType { compilerOptions { freeCompilerArgs.addAll( "-opt-in=kotlin.time.ExperimentalTime", - "-Xuse-fir-lt=false", ) freeCompilerArgs.add("-Xcontext-parameters") } From 0956133bad96981e091eeaa4cf5a14b19d9fb5b3 Mon Sep 17 00:00:00 2001 From: Marco <73824299+MarcoFratta@users.noreply.github.com> Date: Wed, 26 Nov 2025 22:53:17 +0100 Subject: [PATCH 047/196] feat: remove CommitMessageInspectionProfile from vcs.xml --- .idea/vcs.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/vcs.xml b/.idea/vcs.xml index e7dbf5c4f7..b3f968953f 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -5,4 +5,4 @@ - \ No newline at end of file + From cd0c94443f0e6032fdf0a53a5a7439e544e81341 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 19:20:06 +0100 Subject: [PATCH 048/196] fix: fix cpd errors --- alchemist-dsl-processor/build.gradle.kts | 1 + .../dsl/processor/ConstructorParamBuilder.kt | 290 ++++------------ .../dsl/processor/DefaultValueAnalyzer.kt | 33 +- .../dsl/processor/DslBuilderProcessor.kt | 321 +++++++----------- .../dsl/processor/FunctionGenerator.kt | 159 ++------- .../dsl/processor/GenerationContext.kt | 41 +++ 6 files changed, 272 insertions(+), 573 deletions(-) create mode 100644 alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt diff --git a/alchemist-dsl-processor/build.gradle.kts b/alchemist-dsl-processor/build.gradle.kts index 5be2e4baa2..70622c432a 100644 --- a/alchemist-dsl-processor/build.gradle.kts +++ b/alchemist-dsl-processor/build.gradle.kts @@ -3,6 +3,7 @@ import Libs.alchemist plugins { id("kotlin-multiplatform-convention") } + kotlin { jvm() sourceSets { diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 467a523279..9be0aed7e5 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -3,53 +3,15 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter -/** - * Builds constructor parameter expressions for DSL builder functions. - */ object ConstructorParamBuilder { - /** - * Builds the list of constructor parameter expressions. - * - * @param allParameters All constructor parameters - * @param remainingParams Parameters that are not injected - * @param paramsToSkip Set of parameter indices to skip - * @param paramNames Names of remaining parameters - * @param injectionIndices Map of injection types to parameter indices - * @param injectedParamNames Map of injection types to parameter names - * @param annotationValues Annotation values from BuildDsl - * @param typeParamNames Type parameter names - * @param contextType The type of context - * @param hasContextParams Whether context parameters are present - * @param contextParamName Name of the context parameter - * @param injectedParamTypes Map of injection types to parameter types - * @return List of constructor parameter expressions - */ fun buildConstructorParams( - allParameters: List, - remainingParams: List, - paramsToSkip: Set, - paramNames: List, - injectionIndices: Map, - injectedParamNames: Map, - annotationValues: Map, + constructorInfo: ConstructorInfo, + injectionContext: InjectionContext, typeParamNames: List, - contextType: ContextType, - hasContextParams: Boolean = false, - contextParamName: String = "ctx", - injectedParamTypes: Map = emptyMap(), ): List = buildConstructorParamsInternal( - allParameters, - remainingParams, - paramsToSkip, - paramNames, - injectionIndices, - injectedParamNames, - annotationValues, + constructorInfo, + injectionContext, typeParamNames, - injectedParamTypes, - hasContextParams, - contextType, - contextParamName, ) private fun isInjectionIndex( @@ -65,15 +27,11 @@ object ConstructorParamBuilder { private fun buildInjectedParam( injectionType: InjectionType, param: KSValueParameter, - hasContextParams: Boolean, - contextType: ContextType, - contextParamName: String, - injectedParamNames: Map, - injectedParamTypes: Map, + injectionContext: InjectionContext, typeParamNames: List, ): String { - val accessor = buildAccessor(injectionType, hasContextParams, contextType, contextParamName, injectedParamNames) - val contextParamType = injectedParamTypes[injectionType] + val accessor = buildAccessor(injectionType, injectionContext) + val contextParamType = injectionContext.paramTypes[injectionType] return if (contextParamType != null && needsCast(param.type, contextParamType, typeParamNames)) { val castType = TypeExtractor.extractTypeString(param.type, typeParamNames) "$accessor as $castType" @@ -82,18 +40,15 @@ object ConstructorParamBuilder { } } - private fun buildAccessor( - injectionType: InjectionType, - hasContextParams: Boolean, - contextType: ContextType, - contextParamName: String, - injectedParamNames: Map, - ): String { - if (!hasContextParams) { - return injectedParamNames[injectionType] ?: getDefaultParamName(injectionType) + private fun buildAccessor(injectionType: InjectionType, injectionContext: InjectionContext): String { + if (!injectionContext.hasContextParams) { + return injectionContext.paramNames[injectionType] ?: getDefaultParamName(injectionType) } - - return ContextAccessor.getAccessor(injectionType, contextType, contextParamName) + return ContextAccessor.getAccessor( + injectionType, + injectionContext.contextType, + injectionContext.contextParamName, + ) } private fun getDefaultParamName(injectionType: InjectionType): String = when (injectionType) { @@ -112,15 +67,12 @@ object ConstructorParamBuilder { typeParamNames: List, ): Boolean { val constructorTypeStr = TypeExtractor.extractTypeString(constructorParamType, typeParamNames) - if (constructorTypeStr == contextParamType) { return false } - val constructorResolved = constructorParamType.resolve() val constructorDecl = constructorResolved.declaration val constructorQualified = constructorDecl.qualifiedName?.asString().orEmpty() - return when { !contextParamType.startsWith(constructorQualified) -> true constructorResolved.arguments.isEmpty() -> false @@ -135,7 +87,6 @@ object ConstructorParamBuilder { ): Boolean { val constructorHasWildcards = constructorTypeStr.contains("<") && (constructorTypeStr.contains("<*") || constructorTypeStr.contains(", *")) - if (constructorHasWildcards) { val contextTypeArgs = if (contextParamType.contains("<")) { contextParamType.substringAfter("<").substringBefore(">") @@ -144,121 +95,58 @@ object ConstructorParamBuilder { } return typeParamNames.any { it in contextTypeArgs } } - return constructorTypeStr != contextParamType } - /** - * Builds constructor parameter expressions for property context. - * - * @param allParameters All constructor parameters - * @param remainingParams Parameters that are not injected - * @param paramsToSkip Set of parameter indices to skip - * @param paramNames Names of remaining parameters - * @param injectionIndices Map of injection types to parameter indices - * @param injectedParamNames Map of injection types to parameter names - * @param annotationValues Annotation values from BuildDsl - * @param typeParamNames Type parameter names - * @param injectedParamTypes Map of injection types to parameter types - * @return List of constructor parameter expressions - */ fun buildConstructorParamsForPropertyContext( - allParameters: List, - remainingParams: List, - paramsToSkip: Set, - paramNames: List, - injectionIndices: Map, - injectedParamNames: Map, - annotationValues: Map, + constructorInfo: ConstructorInfo, + injectionContext: InjectionContext, typeParamNames: List, - injectedParamTypes: Map = emptyMap(), - ): List = buildConstructorParamsInternal( - allParameters, - remainingParams, - paramsToSkip, - paramNames, - injectionIndices, - injectedParamNames, - annotationValues, - typeParamNames, - injectedParamTypes, - hasContextParams = true, - contextType = ContextType.PROPERTY, - contextParamName = "ctx", - ) + ): List { + val propertyContext = injectionContext.copy( + hasContextParams = true, + contextType = ContextType.PROPERTY, + contextParamName = "ctx", + ) + return buildConstructorParamsInternal( + constructorInfo, + propertyContext, + typeParamNames, + ) + } - /** - * Converts constructor parameters to property context accessors. - * - * @param injectionIndices Map of injection types to parameter indices - * @param allParameters All constructor parameters - * @param remainingParams Parameters that are not injected - * @param paramsToSkip Set of parameter indices to skip - * @param paramNames Names of remaining parameters - * @param injectedParamNames Map of injection types to parameter names - * @param annotationValues Annotation values from BuildDsl - * @param typeParamNames Type parameter names - * @param injectedParamTypes Map of injection types to parameter types - * @return List of constructor parameter expressions using property context accessors - */ fun convertToPropertyContextAccessors( - injectionIndices: Map, - allParameters: List, - remainingParams: List, - paramsToSkip: Set, - paramNames: List, - injectedParamNames: Map, - annotationValues: Map, + constructorInfo: ConstructorInfo, + injectionContext: InjectionContext, typeParamNames: List, - injectedParamTypes: Map, - ): List = buildConstructorParamsInternal( - allParameters, - remainingParams, - paramsToSkip, - paramNames, - injectionIndices, - injectedParamNames, - annotationValues, - typeParamNames, - injectedParamTypes, - hasContextParams = true, - contextType = ContextType.PROPERTY, - contextParamName = "ctx", - ) + ): List { + val propertyContext = injectionContext.copy( + hasContextParams = true, + contextType = ContextType.PROPERTY, + contextParamName = "ctx", + ) + return buildConstructorParamsInternal( + constructorInfo, + propertyContext, + typeParamNames, + ) + } private fun buildConstructorParamsInternal( - allParameters: List, - remainingParams: List, - paramsToSkip: Set, - paramNames: List, - injectionIndices: Map, - injectedParamNames: Map, - annotationValues: Map, + constructorInfo: ConstructorInfo, + injectionContext: InjectionContext, typeParamNames: List, - injectedParamTypes: Map, - hasContextParams: Boolean, - contextType: ContextType, - contextParamName: String, ): List { val constructorParams = mutableListOf() var remainingIndex = 0 - - allParameters.forEachIndexed { index, param -> + constructorInfo.allParameters.forEachIndexed { index, param -> val paramExpr = buildParamExpression( index, param, remainingIndex, - remainingParams, - paramsToSkip, - paramNames, - injectionIndices, - injectedParamNames, - injectedParamTypes, - annotationValues, + constructorInfo, + injectionContext, typeParamNames, - hasContextParams, - contextType, - contextParamName, ) constructorParams.add(paramExpr.first) if (paramExpr.second) { @@ -272,74 +160,35 @@ object ConstructorParamBuilder { index: Int, param: KSValueParameter, remainingIndex: Int, - remainingParams: List, - paramsToSkip: Set, - paramNames: List, - injectionIndices: Map, - injectedParamNames: Map, - injectedParamTypes: Map, - annotationValues: Map, + constructorInfo: ConstructorInfo, + injectionContext: InjectionContext, typeParamNames: List, - hasContextParams: Boolean, - contextType: ContextType, - contextParamName: String, ): Pair { - val injectionType = findInjectionType(index, injectionIndices, annotationValues, paramsToSkip) + val injectionType = findInjectionType(index, injectionContext, constructorInfo.paramsToSkip) if (injectionType != null) { - return buildInjectedParamExpression( - injectionType, - param, - hasContextParams, - contextType, - contextParamName, - injectedParamNames, - injectedParamTypes, - typeParamNames, - ) + return buildInjectedParamExpression(injectionType, param, injectionContext, typeParamNames) } - - return buildRegularParamExpression( - index, - remainingIndex, - remainingParams, - paramsToSkip, - paramNames, - ) + return buildRegularParamExpression(index, remainingIndex, constructorInfo) } private fun buildInjectedParamExpression( injectionType: InjectionType, param: KSValueParameter, - hasContextParams: Boolean, - contextType: ContextType, - contextParamName: String, - injectedParamNames: Map, - injectedParamTypes: Map, + injectionContext: InjectionContext, typeParamNames: List, ): Pair { - val accessor = buildInjectedParam( - injectionType, - param, - hasContextParams, - contextType, - contextParamName, - injectedParamNames, - injectedParamTypes, - typeParamNames, - ) + val accessor = buildInjectedParam(injectionType, param, injectionContext, typeParamNames) return Pair(accessor, false) } private fun buildRegularParamExpression( index: Int, remainingIndex: Int, - remainingParams: List, - paramsToSkip: Set, - paramNames: List, + constructorInfo: ConstructorInfo, ): Pair { - if (!paramsToSkip.contains(index)) { - val paramName = paramNames[remainingIndex] - val remainingParam = remainingParams[remainingIndex] + if (!constructorInfo.paramsToSkip.contains(index)) { + val paramName = constructorInfo.paramNames[remainingIndex] + val remainingParam = constructorInfo.remainingParams[remainingIndex] val paramValue = if (remainingParam.isVararg) "*$paramName" else paramName return Pair(paramValue, true) } @@ -348,8 +197,7 @@ object ConstructorParamBuilder { private fun findInjectionType( index: Int, - injectionIndices: Map, - annotationValues: Map, + injectionContext: InjectionContext, paramsToSkip: Set, ): InjectionType? { val injectionTypes = listOf( @@ -361,23 +209,27 @@ object ConstructorParamBuilder { Triple(InjectionType.TIMEDISTRIBUTION, "", false), Triple(InjectionType.FILTER, "", false), ) - - return findInjectionTypeFromList(index, injectionIndices, annotationValues, paramsToSkip, injectionTypes) + return findInjectionTypeFromList(index, injectionContext, paramsToSkip, injectionTypes) } private fun findInjectionTypeFromList( index: Int, - injectionIndices: Map, - annotationValues: Map, + injectionContext: InjectionContext, paramsToSkip: Set, injectionTypes: List>, ): InjectionType? { for ((type, annotationKey, checkAnnotation) in injectionTypes) { val found = if (checkAnnotation) { - isInjectionIndex(type, index, injectionIndices, annotationValues, annotationKey) + isInjectionIndex( + type, + index, + injectionContext.indices, + injectionContext.annotationValues, + annotationKey, + ) } else { - injectionIndices.containsKey(type) && - index == injectionIndices[type] && + injectionContext.indices.containsKey(type) && + index == injectionContext.indices[type] && paramsToSkip.contains(index) } if (found) { diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt index dce5f9ca01..6bf37f5a76 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt @@ -170,27 +170,22 @@ object DefaultValueAnalyzer { return applyReplacements(defaultValue, replacements) } - private fun findConstantReplacements(defaultValue: String): List> { - val replacements = mutableListOf>() - for (constant in MATH_CONSTANTS) { - val pattern = Regex("""\b$constant\b""") - val qualifiedPattern = Regex("""\w+\.$constant\b""") - if (pattern.containsMatchIn(defaultValue) && !qualifiedPattern.containsMatchIn(defaultValue)) { - pattern.findAll(defaultValue).forEach { match -> - if (!isQualifiedBefore(defaultValue, match.range.first)) { - replacements.add(match.range to "kotlin.math.${match.value}") - } - } - } - } - return replacements - } + private fun findConstantReplacements(defaultValue: String): List> = + findMathReplacements(defaultValue, MATH_CONSTANTS) { identifier -> """\b$identifier\b""" } + + private fun findFunctionReplacements(defaultValue: String): List> = + findMathReplacements(defaultValue, MATH_FUNCTIONS) { identifier -> """\b$identifier\s*\(""" } - private fun findFunctionReplacements(defaultValue: String): List> { + private fun findMathReplacements( + defaultValue: String, + identifiers: Set, + patternBuilder: (String) -> String, + ): List> { val replacements = mutableListOf>() - for (function in MATH_FUNCTIONS) { - val pattern = Regex("""\b$function\s*\(""") - val qualifiedPattern = Regex("""\w+\.$function\s*\(""") + for (identifier in identifiers) { + val patternStr = patternBuilder(identifier) + val pattern = Regex(patternStr) + val qualifiedPattern = Regex("""\w+\.""" + patternStr.removePrefix("""\b""")) if (pattern.containsMatchIn(defaultValue) && !qualifiedPattern.containsMatchIn(defaultValue)) { pattern.findAll(defaultValue).forEach { match -> if (!isQualifiedBefore(defaultValue, match.range.first)) { diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 8c56c3363d..2aaccfb0d1 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -13,9 +13,6 @@ import it.unibo.alchemist.boundary.dsl.BuildDsl import java.io.PrintWriter import java.nio.charset.StandardCharsets -/** - * KSP symbol processor that generates DSL builder functions for classes annotated with [BuildDsl]. - */ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) : SymbolProcessor { override fun process(resolver: Resolver): List { logger.info("DslBuilderProcessor: Starting processing") @@ -92,69 +89,35 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger.info("DslBuilderProcessor: Parameter $index: ${param.name?.asString()} : $typeName") } - val injectionIndices = ParameterInjector.findInjectionIndices(parameters) - logger.info("DslBuilderProcessor: Injection indices: $injectionIndices") - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - logger.info("DslBuilderProcessor: Determined context type: $contextType (manual scope was: '$manualScope')") - val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues, contextType) - val remainingParams = parameters.filterIndexed { index, _ -> !paramsToSkip.contains(index) } - - val containingFile = classDecl.containingFile - val dependencies = if (containingFile != null) { - Dependencies(true, containingFile) - } else { - Dependencies.ALL_FILES - } - - val fileName = functionName.replaceFirstChar { it.uppercaseChar() } + "Helper" - - val file = codeGenerator.createNewFile( - dependencies = dependencies, - packageName = ProcessorConfig.GENERATED_PACKAGE, - fileName = fileName, - ) - - PrintWriter(file, true, StandardCharsets.UTF_8).use { writer -> - writeGeneratedCode( - writer, - classDecl, - functionName, - remainingParams, - parameters, - paramsToSkip, - injectionIndices, - annotationValues, - contextType, - ) - } + val generationContext = buildGenerationContext(classDecl, functionName, parameters, annotationValues) + writeGeneratedFile(classDecl, generationContext) } - private fun writeGeneratedCode( - writer: PrintWriter, + private fun buildGenerationContext( classDecl: KSClassDeclaration, functionName: String, - remainingParams: List, - allParameters: List, - paramsToSkip: Set, - injectionIndices: Map, + parameters: List, annotationValues: Map, - contextType: ContextType, - ) { - writeFileHeader(writer, classDecl, contextType) + ): GenerationContext { + val injectionIndices = ParameterInjector.findInjectionIndices(parameters) + logger.info("DslBuilderProcessor: Injection indices: $injectionIndices") + val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + logger.info("DslBuilderProcessor: Determined context type: $contextType") + val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues, contextType) + val remainingParams = parameters.filterIndexed { index, _ -> !paramsToSkip.contains(index) } val (initialTypeParamNames, initialTypeParamBounds) = TypeExtractor.extractTypeParameters(classDecl) val typeParamNames = initialTypeParamNames.toMutableList() val typeParamBounds = initialTypeParamBounds.toMutableList() - val paramTypes = TypeExtractor.extractParamTypes(remainingParams, typeParamNames) - val defaultValues = DefaultValueAnalyzer.extractAllDefaultValues(remainingParams, classDecl) - val needsMapEnvironment = checkNeedsMapEnvironment(injectionIndices, allParameters) val paramNames = TypeExtractor.extractParamNames(remainingParams) + val defaultValues = DefaultValueAnalyzer.extractAllDefaultValues(remainingParams, classDecl) + val needsMapEnvironment = checkNeedsMapEnvironment(injectionIndices, parameters) val (injectedParams, injectedParamNames, injectedParamTypesMap) = processInjectedParams( injectionIndices, annotationValues, - allParameters, + parameters, typeParamNames, typeParamBounds, ) @@ -164,7 +127,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val hasInjectedParams, injectionIndices, annotationValues, - allParameters, + parameters, typeParamNames, typeParamBounds, initialTypeParamNames, @@ -172,60 +135,78 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val ) addPositionImportIfNeeded(hasInjectedParams, typeParamNames, typeParamBounds, initialTypeParamBounds) - val constructorParams = writeImportsAndFunction( - writer, - typeParamBounds, - paramTypes, - defaultValues, - classDecl, - needsMapEnvironment, - injectedParamTypesMap, - allParameters, - remainingParams, - paramsToSkip, - paramNames, - injectionIndices, - injectedParamNames, - annotationValues, - typeParamNames, - contextType, - hasInjectedParams, - functionName, - classDecl.simpleName.asString(), - injectedParams, - initialTypeParamNames, - initialTypeParamBounds, + + val typeParams = TypeParameterInfo( + names = typeParamNames.toList(), + bounds = typeParamBounds.toList(), + classTypeParamNames = initialTypeParamNames, + classTypeParamBounds = initialTypeParamBounds, ) - val hasNode = injectionIndices.containsKey(InjectionType.NODE) && - annotationValues["injectNode"] as? Boolean ?: true - val hasReaction = injectionIndices.containsKey(InjectionType.REACTION) && - annotationValues["injectReaction"] as? Boolean ?: true + val constructorInfo = ConstructorInfo( + allParameters = parameters, + remainingParams = remainingParams, + paramsToSkip = paramsToSkip, + paramNames = paramNames, + paramTypes = paramTypes, + ) + + val injectionContext = InjectionContext( + indices = injectionIndices, + paramNames = injectedParamNames, + paramTypes = injectedParamTypesMap, + annotationValues = annotationValues, + contextType = contextType, + hasContextParams = hasInjectedParams, + contextParamName = "ctx", + ) + + return GenerationContext( + classDecl = classDecl, + className = classDecl.simpleName.asString(), + functionName = functionName, + typeParams = typeParams, + constructorInfo = constructorInfo, + injectionContext = injectionContext, + injectedParams = injectedParams, + defaultValues = defaultValues, + needsMapEnvironment = needsMapEnvironment, + ) + } + + private fun writeGeneratedFile(classDecl: KSClassDeclaration, context: GenerationContext) { + val containingFile = classDecl.containingFile + val dependencies = if (containingFile != null) { + Dependencies(true, containingFile) + } else { + Dependencies.ALL_FILES + } + + val fileName = context.functionName.replaceFirstChar { it.uppercaseChar() } + "Helper" + + val file = codeGenerator.createNewFile( + dependencies = dependencies, + packageName = ProcessorConfig.GENERATED_PACKAGE, + fileName = fileName, + ) + + PrintWriter(file, true, StandardCharsets.UTF_8).use { writer -> + writeGeneratedCode(writer, context) + } + } + + private fun writeGeneratedCode(writer: PrintWriter, context: GenerationContext) { + writeFileHeader(writer, context.classDecl, context.injectionContext.contextType) + + val constructorParams = writeImportsAndFunction(writer, context) + + val hasNode = context.injectionContext.indices.containsKey(InjectionType.NODE) && + context.injectionContext.annotationValues["injectNode"] as? Boolean ?: true + val hasReaction = context.injectionContext.indices.containsKey(InjectionType.REACTION) && + context.injectionContext.annotationValues["injectReaction"] as? Boolean ?: true if (hasNode && !hasReaction) { - writePropertyContextFunction( - writer, - typeParamBounds, - paramTypes, - defaultValues, - classDecl, - needsMapEnvironment, - injectedParamTypesMap, - allParameters, - remainingParams, - paramsToSkip, - paramNames, - injectionIndices, - injectedParamNames, - annotationValues, - typeParamNames, - functionName, - classDecl.simpleName.asString(), - injectedParams, - initialTypeParamNames, - initialTypeParamBounds, - constructorParams, - ) + writePropertyContextFunction(writer, context, constructorParams) } } @@ -402,75 +383,38 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val } } - private fun writeImportsAndFunction( - writer: PrintWriter, - finalTypeParamBounds: List, - paramTypes: List, - defaultValues: List, - classDecl: KSClassDeclaration, - needsMapEnvironment: Boolean, - injectedParamTypesMap: Map, - allParameters: List, - remainingParams: List, - paramsToSkip: Set, - paramNames: List, - injectionIndices: Map, - injectedParamNames: Map, - annotationValues: Map, - typeParamNames: List, - contextType: ContextType, - hasInjectedParams: Boolean, - functionName: String, - className: String, - injectedParams: List>, - initialTypeParamNames: List, - initialTypeParamBounds: List, - ): List { + private fun writeImportsAndFunction(writer: PrintWriter, context: GenerationContext): List { ImportManager.writeImports( writer, - finalTypeParamBounds, - paramTypes, - defaultValues, - classDecl, - needsMapEnvironment, - injectedParamTypesMap.values.toList(), + context.typeParams.bounds, + context.constructorInfo.paramTypes, + context.defaultValues, + context.classDecl, + context.needsMapEnvironment, + context.injectionContext.paramTypes.values.toList(), ) val constructorParams = FunctionGenerator.buildConstructorParams( - allParameters, - remainingParams, - paramsToSkip, - paramNames, - injectionIndices, - injectedParamNames, - annotationValues, - typeParamNames, - contextType, - hasInjectedParams, - "ctx", - injectedParamTypesMap, + context.constructorInfo, + context.injectionContext, + context.typeParams.names, ) val functionSignature = FunctionGenerator.buildFunctionSignature( - functionName, - finalTypeParamBounds, - typeParamNames, - className, - remainingParams, - paramNames, - paramTypes, - injectedParams, - contextType, - initialTypeParamNames, - initialTypeParamBounds, + context.functionName, + context.className, + context.typeParams, + context.constructorInfo, + context.injectedParams, + context.injectionContext.contextType, ) writer.println(functionSignature) val constructorCall = FunctionGenerator.buildConstructorCall( - className, - typeParamNames, + context.className, + context.typeParams.names, constructorParams, - initialTypeParamNames, + context.typeParams.classTypeParamNames, ) writer.println(" $constructorCall") return constructorParams @@ -478,57 +422,44 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val private fun writePropertyContextFunction( writer: PrintWriter, - finalTypeParamBounds: List, - paramTypes: List, - @Suppress("UNUSED_PARAMETER") defaultValues: List, - @Suppress("UNUSED_PARAMETER") classDecl: KSClassDeclaration, - @Suppress("UNUSED_PARAMETER") needsMapEnvironment: Boolean, - injectedParamTypesMap: Map, - allParameters: List, - remainingParams: List, - paramsToSkip: Set, - paramNames: List, - injectionIndices: Map, - injectedParamNames: Map, - annotationValues: Map, - typeParamNames: List, - functionName: String, - className: String, - @Suppress("UNUSED_PARAMETER") injectedParams: List>, - initialTypeParamNames: List, - @Suppress("UNUSED_PARAMETER") initialTypeParamBounds: List, + context: GenerationContext, @Suppress("UNUSED_PARAMETER") constructorParams: List, ) { writer.println() - val (tParam, pParam) = TypeParameterHandler.findTAndPParams(typeParamNames, finalTypeParamBounds) - val pVariance = FunctionGenerator.extractVarianceFromBound(pParam, finalTypeParamBounds) + val (tParam, pParam) = TypeParameterHandler.findTAndPParams( + context.typeParams.names, + context.typeParams.bounds, + ) + val pVariance = FunctionGenerator.extractVarianceFromBound(pParam, context.typeParams.bounds) val pWithVariance = if (pVariance.isNotEmpty()) "$pVariance $pParam" else pParam - val functionTypeParamString = TypeParameterHandler.buildTypeParamString(finalTypeParamBounds) - val returnType = TypeParameterHandler.buildReturnType(className, initialTypeParamNames) + val functionTypeParamString = TypeParameterHandler.buildTypeParamString(context.typeParams.bounds) + val returnType = TypeParameterHandler.buildReturnType( + context.className, + context.typeParams.classTypeParamNames, + ) val contextPart = "context(ctx: ${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}<$tParam, $pWithVariance>) " - val functionParams = FunctionGenerator.buildFunctionParams(remainingParams, paramNames, paramTypes) + val functionParams = FunctionGenerator.buildFunctionParams( + context.constructorInfo.remainingParams, + context.constructorInfo.paramNames, + context.constructorInfo.paramTypes, + ) - val functionSignature = "${contextPart}fun$functionTypeParamString $functionName$functionParams: $returnType =" + val functionSignature = "${contextPart}fun$functionTypeParamString " + + "${context.functionName}$functionParams: $returnType =" writer.println(functionSignature) val propertyContextConstructorParams = ConstructorParamBuilder.convertToPropertyContextAccessors( - injectionIndices, - allParameters, - remainingParams, - paramsToSkip, - paramNames, - injectedParamNames, - annotationValues, - typeParamNames, - injectedParamTypesMap, + context.constructorInfo, + context.injectionContext, + context.typeParams.names, ) val constructorCall = FunctionGenerator.buildConstructorCall( - className, - typeParamNames, + context.className, + context.typeParams.names, propertyContextConstructorParams, - initialTypeParamNames, + context.typeParams.classTypeParamNames, ) writer.println(" $constructorCall") } diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt index 27fb70579d..0d64478f7f 100644 --- a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt @@ -3,49 +3,30 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter -/** - * Generates function signatures and constructor calls for DSL builder functions. - */ object FunctionGenerator { - /** - * Builds the function signature for a DSL builder function. - * - * @param functionName The name of the function to generate - * @param typeParamBounds Type parameter bounds - * @param typeParamNames Type parameter names - * @param className The name of the class being constructed - * @param remainingParams Parameters that are not injected - * @param paramNames Names of the remaining parameters - * @param paramTypes Types of the remaining parameters - * @param injectedParams List of injected parameter names and types - * @param contextType The type of context (deployment or program) - * @param classTypeParamNames Type parameter names from the class declaration - * @return The complete function signature string - */ fun buildFunctionSignature( functionName: String, - typeParamBounds: List, - typeParamNames: List, className: String, - remainingParams: List, - paramNames: List, - paramTypes: List, + typeParams: TypeParameterInfo, + constructorInfo: ConstructorInfo, injectedParams: List>, contextType: ContextType, - classTypeParamNames: List = typeParamNames, - classTypeParamBounds: List = typeParamBounds, ): String { val (finalTypeParamNames, finalTypeParamBounds) = TypeParameterHandler.prepareTypeParams( - typeParamNames, - typeParamBounds, + typeParams.names, + typeParams.bounds, injectedParams, - classTypeParamBounds, + typeParams.classTypeParamBounds, ) val functionTypeParamString = TypeParameterHandler.buildTypeParamString(finalTypeParamBounds) - val returnType = TypeParameterHandler.buildReturnType(className, classTypeParamNames) + val returnType = TypeParameterHandler.buildReturnType(className, typeParams.classTypeParamNames) val contextPart = buildContextPart(injectedParams, contextType, finalTypeParamNames, finalTypeParamBounds) - val functionParams = buildFunctionParams(remainingParams, paramNames, paramTypes) + val functionParams = buildFunctionParams( + constructorInfo.remainingParams, + constructorInfo.paramNames, + constructorInfo.paramTypes, + ) val receiverPart = buildReceiverPart(injectedParams, contextType) return "${contextPart}fun$functionTypeParamString $receiverPart$functionName$functionParams: $returnType =" @@ -86,13 +67,6 @@ object FunctionGenerator { return "context(ctx: $contextTypeName) " } - /** - * Extracts variance annotation (in/out) from a type parameter bound. - * - * @param paramName The name of the type parameter - * @param typeParamBounds List of type parameter bounds - * @return The variance string ("in", "out", or empty string) - */ fun extractVarianceFromBound(paramName: String, typeParamBounds: List): String { val paramIndex = typeParamBounds.indexOfFirst { it.startsWith("$paramName:") } if (paramIndex < 0) { @@ -116,14 +90,6 @@ object FunctionGenerator { } } - /** - * Builds the function parameter list string. - * - * @param remainingParams Parameters that are not injected - * @param paramNames Names of the remaining parameters - * @param paramTypes Types of the remaining parameters - * @return The function parameter list string - */ fun buildFunctionParams( remainingParams: List, paramNames: List, @@ -152,62 +118,16 @@ object FunctionGenerator { @Suppress("UNUSED_PARAMETER") contextType: ContextType, ): String = EMPTY_RECEIVER - /** - * Builds the list of constructor parameter expressions. - * - * @param allParameters All constructor parameters - * @param remainingParams Parameters that are not injected - * @param paramsToSkip Set of parameter indices to skip - * @param paramNames Names of remaining parameters - * @param injectionIndices Map of injection types to parameter indices - * @param injectedParamNames Map of injection types to parameter names - * @param annotationValues Annotation values from BuildDsl - * @param typeParamNames Type parameter names - * @param contextType The type of context - * @param hasContextParams Whether context parameters are present - * @param contextParamName Name of the context parameter - * @param injectedParamTypes Map of injection types to parameter types - * @return List of constructor parameter expressions - */ - // CPD-OFF: Function signature duplication is necessary for API delegation fun buildConstructorParams( - allParameters: List, - remainingParams: List, - paramsToSkip: Set, - paramNames: List, - injectionIndices: Map, - injectedParamNames: Map, - annotationValues: Map, + constructorInfo: ConstructorInfo, + injectionContext: InjectionContext, typeParamNames: List, - contextType: ContextType, - hasContextParams: Boolean = false, - contextParamName: String = "ctx", - injectedParamTypes: Map = emptyMap(), ): List = ConstructorParamBuilder.buildConstructorParams( - allParameters, - remainingParams, - paramsToSkip, - paramNames, - injectionIndices, - injectedParamNames, - annotationValues, + constructorInfo, + injectionContext, typeParamNames, - contextType, - hasContextParams, - contextParamName, - injectedParamTypes, ) - // CPD-ON - /** - * Builds the constructor call expression. - * - * @param className The name of the class - * @param typeParamNames Type parameter names - * @param constructorParams List of constructor parameter expressions - * @param classTypeParamNames Type parameter names from the class declaration - * @return The constructor call string - */ fun buildConstructorCall( className: String, typeParamNames: List, @@ -231,63 +151,22 @@ object FunctionGenerator { return defaultValueExpr?.let { " = $it" }.orEmpty() } - /** - * Collects type parameters needed for a type reference. - * - * @param typeRef The type reference to analyze - * @param existingTypeParamNames List of existing type parameter names - * @return Set of needed type parameter names - */ fun collectNeededTypeParams(typeRef: KSTypeReference, existingTypeParamNames: List): Set = TypeParameterHandler.collectNeededTypeParams(typeRef, existingTypeParamNames) - /** - * Builds the type string for a context parameter, handling type arguments and bounds. - * - * @param typeRef The type reference to build from - * @param typeParamNames Mutable list of type parameter names (may be modified) - * @param typeParamBounds Mutable list of type parameter bounds (may be modified) - * @return The type string for the context parameter - */ fun buildContextParamType( typeRef: KSTypeReference, typeParamNames: MutableList, typeParamBounds: MutableList, ): String = TypeArgumentProcessor.buildContextParamType(typeRef, typeParamNames, typeParamBounds) - /** - * Builds constructor parameter expressions for property context. - * - * @param allParameters All constructor parameters - * @param remainingParams Parameters that are not injected - * @param paramsToSkip Set of parameter indices to skip - * @param paramNames Names of remaining parameters - * @param injectionIndices Map of injection types to parameter indices - * @param injectedParamNames Map of injection types to parameter names - * @param annotationValues Annotation values from BuildDsl - * @param typeParamNames Type parameter names - * @param injectedParamTypes Map of injection types to parameter types - * @return List of constructor parameter expressions - */ fun buildConstructorParamsForPropertyContext( - allParameters: List, - remainingParams: List, - paramsToSkip: Set, - paramNames: List, - injectionIndices: Map, - injectedParamNames: Map, - annotationValues: Map, + constructorInfo: ConstructorInfo, + injectionContext: InjectionContext, typeParamNames: List, - injectedParamTypes: Map = emptyMap(), ): List = ConstructorParamBuilder.buildConstructorParamsForPropertyContext( - allParameters, - remainingParams, - paramsToSkip, - paramNames, - injectionIndices, - injectedParamNames, - annotationValues, + constructorInfo, + injectionContext, typeParamNames, - injectedParamTypes, ) } diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt new file mode 100644 index 0000000000..394ea1e761 --- /dev/null +++ b/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt @@ -0,0 +1,41 @@ +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSValueParameter + +data class TypeParameterInfo( + val names: List, + val bounds: List, + val classTypeParamNames: List = names, + val classTypeParamBounds: List = bounds, +) + +data class ConstructorInfo( + val allParameters: List, + val remainingParams: List, + val paramsToSkip: Set, + val paramNames: List, + val paramTypes: List, +) + +data class InjectionContext( + val indices: Map, + val paramNames: Map, + val paramTypes: Map, + val annotationValues: Map, + val contextType: ContextType, + val hasContextParams: Boolean = false, + val contextParamName: String = "ctx", +) + +data class GenerationContext( + val classDecl: KSClassDeclaration, + val className: String, + val functionName: String, + val typeParams: TypeParameterInfo, + val constructorInfo: ConstructorInfo, + val injectionContext: InjectionContext, + val injectedParams: List>, + val defaultValues: List, + val needsMapEnvironment: Boolean, +) From ea828ba606a894bef680b2e0bede6b83d8dc4137 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 19:25:17 +0100 Subject: [PATCH 049/196] fix: fix cpd errors in alchemist-loading --- .../it/unibo/alchemist/dsl/TestComparators.kt | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt index 94f6499f04..6437057737 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt @@ -132,12 +132,17 @@ object TestComparators { } } -private fun shouldUseDefaultSteps( +private const val DEFAULT_STEPS = 3000L + +private fun computeEffectiveSteps( includeRuntime: Boolean, steps: Long?, targetTime: Double?, stableForSteps: Pair?, -): Boolean = includeRuntime && steps == null && targetTime == null && stableForSteps == null +): Long? { + val shouldUseDefault = includeRuntime && steps == null && targetTime == null && stableForSteps == null + return if (shouldUseDefault) DEFAULT_STEPS else steps +} /** * Extension function for easier test writing with static comparison only. @@ -168,17 +173,12 @@ fun Loader.shouldEqual( stableForSteps: Pair? = null, timeTolerance: Double = 0.01, ) { - val effectiveSteps = if (shouldUseDefaultSteps(includeRuntime, steps, targetTime, stableForSteps)) { - 3000L - } else { - steps - } @Suppress("UNCHECKED_CAST") TestComparators.compare( this, other, includeRuntime, - effectiveSteps, + computeEffectiveSteps(includeRuntime, steps, targetTime, stableForSteps), targetTime, stableForSteps, timeTolerance, @@ -217,17 +217,12 @@ fun (() -> Loader).shouldEqual( stableForSteps: Pair? = null, timeTolerance: Double = 0.01, ) { - val effectiveSteps = if (shouldUseDefaultSteps(includeRuntime, steps, targetTime, stableForSteps)) { - 3000L - } else { - steps - } @Suppress("UNCHECKED_CAST") TestComparators.compare( this, yamlResource, includeRuntime, - effectiveSteps, + computeEffectiveSteps(includeRuntime, steps, targetTime, stableForSteps), targetTime, stableForSteps, timeTolerance, From c64da66a7cebfe4f33445bf8b9700ea7fea9a62c Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 19:39:44 +0100 Subject: [PATCH 050/196] fix: rename sources dir names --- alchemist-dsl-processor/build.gradle.kts | 3 --- .../unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt | 0 .../alchemist/boundary/dsl/processor/ConstructorFinder.kt | 0 .../boundary/dsl/processor/ConstructorParamBuilder.kt | 0 .../unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt | 0 .../alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt | 0 .../alchemist/boundary/dsl/processor/DslBuilderProcessor.kt | 0 .../boundary/dsl/processor/DslBuilderProcessorProvider.kt | 0 .../alchemist/boundary/dsl/processor/FunctionGenerator.kt | 0 .../alchemist/boundary/dsl/processor/GenerationContext.kt | 0 .../it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt | 0 .../alchemist/boundary/dsl/processor/ParameterInjector.kt | 0 .../unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt | 0 .../alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt | 0 .../it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt | 0 .../alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt | 0 .../alchemist/boundary/dsl/processor/TypeParameterHandler.kt | 0 .../com.google.devtools.ksp.processing.SymbolProcessorProvider | 0 .../alchemist/boundary/dsl/processor/ContextAccessorTest.kt | 0 .../alchemist/boundary/dsl/processor/ParameterInjectorTest.kt | 0 .../alchemist/boundary/dsl/processor/ProcessorConfigTest.kt | 0 .../boundary/dsl/processor/TypeParameterHandlerTest.kt | 0 22 files changed, 3 deletions(-) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt (100%) rename alchemist-dsl-processor/src/{main => jvmMain}/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider (100%) rename alchemist-dsl-processor/src/{test => jvmTest}/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt (100%) rename alchemist-dsl-processor/src/{test => jvmTest}/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt (100%) rename alchemist-dsl-processor/src/{test => jvmTest}/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt (100%) rename alchemist-dsl-processor/src/{test => jvmTest}/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt (100%) diff --git a/alchemist-dsl-processor/build.gradle.kts b/alchemist-dsl-processor/build.gradle.kts index 70622c432a..f0fa6c349c 100644 --- a/alchemist-dsl-processor/build.gradle.kts +++ b/alchemist-dsl-processor/build.gradle.kts @@ -12,15 +12,12 @@ kotlin { api(alchemist("api")) implementation(libs.ksp.api) } - kotlin.srcDir("src/main/kotlin") - resources.srcDir("src/main/resources") } val jvmTest by getting { dependencies { implementation(libs.bundles.testing.compile) runtimeOnly(libs.bundles.testing.runtimeOnly) } - kotlin.srcDir("src/test/kotlin") } } } diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt diff --git a/alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt similarity index 100% rename from alchemist-dsl-processor/src/main/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt diff --git a/alchemist-dsl-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/alchemist-dsl-processor/src/jvmMain/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider similarity index 100% rename from alchemist-dsl-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider rename to alchemist-dsl-processor/src/jvmMain/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt similarity index 100% rename from alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt rename to alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt similarity index 100% rename from alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt rename to alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt similarity index 100% rename from alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt rename to alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt diff --git a/alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt similarity index 100% rename from alchemist-dsl-processor/src/test/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt rename to alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt From c7127eeaef07d5a64536966ac6036866e11ae90b Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 20:53:13 +0100 Subject: [PATCH 051/196] style: fix vertical spacing inconsistencies --- .../boundary/dsl/processor/BoundProcessor.kt | 7 +- .../dsl/processor/ConstructorFinder.kt | 8 +- .../dsl/processor/ConstructorParamBuilder.kt | 12 ++- .../boundary/dsl/processor/ContextAccessor.kt | 8 +- .../dsl/processor/DefaultValueAnalyzer.kt | 24 +++--- .../dsl/processor/DslBuilderProcessor.kt | 72 +++++------------- .../dsl/processor/FunctionGenerator.kt | 31 +++----- .../boundary/dsl/processor/ImportManager.kt | 2 - .../dsl/processor/ParameterInjector.kt | 76 ++++++------------- .../boundary/dsl/processor/ProcessorConfig.kt | 1 + .../dsl/processor/TypeArgumentProcessor.kt | 40 +++++----- .../boundary/dsl/processor/TypeExtractor.kt | 5 +- .../dsl/processor/TypeHierarchyChecker.kt | 13 +--- .../dsl/processor/TypeParameterHandler.kt | 7 -- .../dsl/processor/ContextAccessorTest.kt | 45 ++++++----- .../dsl/processor/ParameterInjectorTest.kt | 61 ++++++++------- 16 files changed, 175 insertions(+), 237 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt index 4fd8d795e0..f9ce44b4ed 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt @@ -19,7 +19,6 @@ object BoundProcessor { val resolved = bound.resolve() val decl = resolved.declaration val qualifiedName = decl.qualifiedName?.asString() - if (qualifiedName != null) { val arguments = resolved.arguments val typeString = if (arguments.isNotEmpty()) { @@ -30,16 +29,16 @@ object BoundProcessor { } else { qualifiedName } - val nullableSuffix = if (resolved.isMarkedNullable) "?" else "" val result = "$typeString$nullableSuffix" return replaceClassTypeParamReferences(result, classTypeParamNames) } - val result = TypeExtractor.extractTypeString(bound, emptyList()) return replaceClassTypeParamReferences(result, classTypeParamNames) } + // Bring each type argument back into a printable form, + // handling variance explicitly. private fun formatTypeArgument(arg: KSTypeArgument, classTypeParamNames: List): String = when { arg.type == null -> "*" arg.variance == Variance.STAR -> "*" @@ -66,6 +65,8 @@ object BoundProcessor { } private fun replaceClassTypeParamReferences(boundStr: String, classTypeParamNames: List): String { + // Strip redundant qualification when the matcher references + // the same class-level type parameter if (classTypeParamNames.isEmpty()) { return boundStr } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt index 36c99f19f4..d92ad9e502 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt @@ -15,12 +15,15 @@ object ConstructorFinder { * @param classDecl The class declaration to find a constructor for * @return The found constructor, or null if no suitable constructor exists */ + // Prefer the primary constructor, but if it's missing or not public, pick the public constructor with the most params. fun findConstructor(classDecl: KSClassDeclaration): KSFunctionDeclaration? { val primaryConstructor = classDecl.primaryConstructor - if (primaryConstructor != null && isPublicConstructor(primaryConstructor)) { + if ( + primaryConstructor != null && + isPublicConstructor(primaryConstructor) + ) { return primaryConstructor } - val constructors = classDecl.getAllFunctions() .filter { function -> val simpleName = function.simpleName.asString() @@ -28,7 +31,6 @@ object ConstructorFinder { isPublicConstructor(function) } .sortedByDescending { it.parameters.size } - return constructors.firstOrNull() } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 9be0aed7e5..33dc177e67 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -4,6 +4,10 @@ import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter object ConstructorParamBuilder { + /** + * Walks constructor parameters in order and either injects context values + * or maps supplied arguments. + */ fun buildConstructorParams( constructorInfo: ConstructorInfo, injectionContext: InjectionContext, @@ -105,7 +109,7 @@ object ConstructorParamBuilder { ): List { val propertyContext = injectionContext.copy( hasContextParams = true, - contextType = ContextType.PROPERTY, + contextType = ContextType.PROPERTY_CONTEXT, contextParamName = "ctx", ) return buildConstructorParamsInternal( @@ -120,14 +124,14 @@ object ConstructorParamBuilder { injectionContext: InjectionContext, typeParamNames: List, ): List { - val propertyContext = injectionContext.copy( + val propertyCONTEXTContext = injectionContext.copy( hasContextParams = true, - contextType = ContextType.PROPERTY, + contextType = ContextType.PROPERTY_CONTEXT, contextParamName = "ctx", ) return buildConstructorParamsInternal( constructorInfo, - propertyContext, + propertyCONTEXTContext, typeParamNames, ) } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt index e2de57ee99..aa65637cdb 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt @@ -14,15 +14,15 @@ object ContextAccessor { */ fun getAccessor(injectionType: InjectionType, contextType: ContextType, contextParamName: String = "ctx"): String = when (contextType) { - ContextType.SIMULATION -> getSimulationAccessor(injectionType, contextParamName) + ContextType.SIMULATION_CONTEXT -> getSimulationAccessor(injectionType, contextParamName) ContextType.EXPORTER_CONTEXT -> getExporterContextAccessor(injectionType, contextParamName) ContextType.GLOBAL_PROGRAMS_CONTEXT -> getGlobalProgramsContextAccessor(injectionType, contextParamName) ContextType.OUTPUT_MONITORS_CONTEXT -> getOutputMonitorsContextAccessor(injectionType, contextParamName) ContextType.TERMINATORS_CONTEXT -> getTerminatorsContextAccessor(injectionType, contextParamName) - ContextType.DEPLOYMENT -> getDeploymentsContextAccessor(injectionType, contextParamName) + ContextType.DEPLOYMENTS_CONTEXT -> getDeploymentsContextAccessor(injectionType, contextParamName) ContextType.DEPLOYMENT_CONTEXT -> getDeploymentContextAccessor(injectionType, contextParamName) - ContextType.PROGRAM -> getProgramAccessor(injectionType, contextParamName) - ContextType.PROPERTY -> getPropertyAccessor(injectionType, contextParamName) + ContextType.PROGRAM_CONTEXT -> getProgramAccessor(injectionType, contextParamName) + ContextType.PROPERTY_CONTEXT -> getPropertyAccessor(injectionType, contextParamName) } private fun getSimulationAccessor(injectionType: InjectionType, contextParamName: String): String = diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt index 6bf37f5a76..0ddc831b3f 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt @@ -46,27 +46,24 @@ object DefaultValueAnalyzer { val neededImports = mutableSetOf() val defaultValueText = defaultValues.joinToString(" ") val sourceImports = getSourceFileImports(classDecl) - neededImports.addAll(extractIdentifierImports(defaultValueText, sourceImports)) - return neededImports } private fun extractIdentifierImports(defaultValueText: String, sourceImports: List): Set { val neededImports = mutableSetOf() - + // Use regex to find potential class/function identifiers so we can detect missing imports. val identifierPattern = Regex("""\b([A-Z][a-zA-Z0-9]*)\b""") val matches = identifierPattern.findAll(defaultValueText) for (match in matches) { val identifier = match.groupValues[1] - if (identifier !in MATH_CONSTANTS && identifier !in MATH_FUNCTIONS && identifier !in BUILTIN_TYPES) { + if (!(identifier in MATH_CONSTANTS || identifier in MATH_FUNCTIONS || identifier in BUILTIN_TYPES)) { val qualifiedPattern = Regex("""\w+\.$identifier\b""") if (!qualifiedPattern.containsMatchIn(defaultValueText)) { addImportIfNeeded(identifier, defaultValueText, sourceImports, null, neededImports) } } } - return neededImports } @@ -114,7 +111,6 @@ object DefaultValueAnalyzer { if (explicitImport != null) { return "import $explicitImport" } - return if (defaultPackage != null) { "import $defaultPackage.$identifier" } else { @@ -162,11 +158,9 @@ object DefaultValueAnalyzer { val replacements = mutableListOf>() replacements.addAll(findConstantReplacements(defaultValue)) replacements.addAll(findFunctionReplacements(defaultValue)) - if (replacements.isEmpty()) { return defaultValue } - return applyReplacements(defaultValue, replacements) } @@ -182,6 +176,8 @@ object DefaultValueAnalyzer { patternBuilder: (String) -> String, ): List> { val replacements = mutableListOf>() + // Patterns above match both qualified and + // unqualified usages so we only rewrite the unqualified ones. for (identifier in identifiers) { val patternStr = patternBuilder(identifier) val pattern = Regex(patternStr) @@ -198,7 +194,7 @@ object DefaultValueAnalyzer { } private fun isQualifiedBefore(defaultValue: String, index: Int): Boolean { - val before = defaultValue.substring(0, index) + val before = defaultValue.take(index) return before.endsWith(".") || before.endsWith("::") } @@ -211,6 +207,13 @@ object DefaultValueAnalyzer { return result } + // Fallback regex-based extractor when the AST information is not enough. + // KSP doesn’t always expose the default-value expression + // it parsed, especially when the parameter belongs to a library or + // comes from metadata where the AST node isn’t available, + // we can’t rely solely on the AST-based extractor. + // In those cases we still want to keep generating the literal default + // (for imports, signatures, etc.) private fun tryExtractSimpleDefault(sourceCode: String, paramName: String): String? { val escapedName = Regex.escape(paramName) val modifierPattern = """(?:private\s+|public\s+|protected\s+|internal\s+)?""" @@ -281,10 +284,8 @@ object DefaultValueAnalyzer { private fun extractBalancedExpression(sourceCode: String, startIndex: Int): String? { if (startIndex >= sourceCode.length) return null - val state = ExtractionState(startIndex) val result = StringBuilder() - while (state.index < sourceCode.length) { val char = sourceCode[state.index] val shouldContinue = processCharacter(char, sourceCode, state, result) @@ -293,7 +294,6 @@ object DefaultValueAnalyzer { } state.index++ } - return result.toString().trim().takeIf { it.isNotEmpty() } } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 2aaccfb0d1..0b844c6371 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -17,12 +17,10 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val override fun process(resolver: Resolver): List { logger.info("DslBuilderProcessor: Starting processing") logger.info("DslBuilderProcessor: BuildDsl qualified name: ${BuildDsl::class.qualifiedName}") - val annotationName = BuildDsl::class.qualifiedName ?: return emptyList() val symbols = resolver.getSymbolsWithAnnotation(annotationName) val symbolList = symbols.toList() logger.info("DslBuilderProcessor: Found ${symbolList.size} symbols with @BuildDsl annotation") - symbolList.forEach { symbol -> val qualifiedName = when (symbol) { is KSClassDeclaration -> symbol.qualifiedName?.asString() ?: "unknown" @@ -30,15 +28,12 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val } logger.info("DslBuilderProcessor: Found symbol: $qualifiedName") } - val ret = symbolList.filter { !it.validate() }.toList() - symbolList .filter { it is KSClassDeclaration && it.validate() } .forEach { classDecl -> processClass(classDecl as KSClassDeclaration) } - return ret } @@ -56,7 +51,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val private fun processClass(classDecl: KSClassDeclaration) { logger.info("DslBuilderProcessor: Processing class ${classDecl.simpleName.asString()}") logger.info("DslBuilderProcessor: Class qualified name: ${classDecl.qualifiedName?.asString()}") - val annotation = classDecl.annotations.firstOrNull { it.shortName.asString() == "BuildDsl" } @@ -64,35 +58,30 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger.warn("Class ${classDecl.simpleName.asString()} has no @BuildDsl annotation") return } - val annotationValues = annotation.arguments .mapNotNull { arg -> arg.name?.asString()?.let { it to arg.value } } .toMap() - logger.info("DslBuilderProcessor: Annotation values: $annotationValues") val manualScope = annotationValues["scope"] as? String logger.info("DslBuilderProcessor: Manual scope from annotation: '$manualScope'") - val functionName = (annotationValues["functionName"] as? String)?.takeIf { it.isNotEmpty() } ?: classDecl.simpleName.asString().replaceFirstChar { it.lowercaseChar() } - val constructor = ConstructorFinder.findConstructor(classDecl) if (constructor == null) { logger.warn("Class ${classDecl.simpleName.asString()} has no usable constructor") return } - val parameters = constructor.parameters logger.info("DslBuilderProcessor: Found constructor with ${parameters.size} parameters") parameters.forEachIndexed { index, param -> val typeName = param.type.resolve().declaration.qualifiedName?.asString() ?: "unknown" logger.info("DslBuilderProcessor: Parameter $index: ${param.name?.asString()} : $typeName") } - val generationContext = buildGenerationContext(classDecl, functionName, parameters, annotationValues) writeGeneratedFile(classDecl, generationContext) } + // Gather all derived state (injections, type params, constructor metadata) before emitting code. private fun buildGenerationContext( classDecl: KSClassDeclaration, functionName: String, @@ -105,7 +94,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger.info("DslBuilderProcessor: Determined context type: $contextType") val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues, contextType) val remainingParams = parameters.filterIndexed { index, _ -> !paramsToSkip.contains(index) } - val (initialTypeParamNames, initialTypeParamBounds) = TypeExtractor.extractTypeParameters(classDecl) val typeParamNames = initialTypeParamNames.toMutableList() val typeParamBounds = initialTypeParamBounds.toMutableList() @@ -113,15 +101,15 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val val paramNames = TypeExtractor.extractParamNames(remainingParams) val defaultValues = DefaultValueAnalyzer.extractAllDefaultValues(remainingParams, classDecl) val needsMapEnvironment = checkNeedsMapEnvironment(injectionIndices, parameters) - - val (injectedParams, injectedParamNames, injectedParamTypesMap) = processInjectedParams( - injectionIndices, - annotationValues, - parameters, - typeParamNames, - typeParamBounds, - ) - + // Track which parameters are injected so we can include them in the signature/context. + val (injectedParams, injectedParamNames, injectedParamTypesMap) = + processInjectedParams( + injectionIndices, + annotationValues, + parameters, + typeParamNames, + typeParamBounds, + ) val hasInjectedParams = injectedParams.isNotEmpty() updateTypeParamsForInjected( hasInjectedParams, @@ -133,16 +121,13 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val initialTypeParamNames, initialTypeParamBounds, ) - addPositionImportIfNeeded(hasInjectedParams, typeParamNames, typeParamBounds, initialTypeParamBounds) - val typeParams = TypeParameterInfo( names = typeParamNames.toList(), bounds = typeParamBounds.toList(), classTypeParamNames = initialTypeParamNames, classTypeParamBounds = initialTypeParamBounds, ) - val constructorInfo = ConstructorInfo( allParameters = parameters, remainingParams = remainingParams, @@ -150,7 +135,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val paramNames = paramNames, paramTypes = paramTypes, ) - val injectionContext = InjectionContext( indices = injectionIndices, paramNames = injectedParamNames, @@ -160,7 +144,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val hasContextParams = hasInjectedParams, contextParamName = "ctx", ) - return GenerationContext( classDecl = classDecl, className = classDecl.simpleName.asString(), @@ -173,7 +156,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val needsMapEnvironment = needsMapEnvironment, ) } - private fun writeGeneratedFile(classDecl: KSClassDeclaration, context: GenerationContext) { val containingFile = classDecl.containingFile val dependencies = if (containingFile != null) { @@ -181,15 +163,12 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val } else { Dependencies.ALL_FILES } - val fileName = context.functionName.replaceFirstChar { it.uppercaseChar() } + "Helper" - val file = codeGenerator.createNewFile( dependencies = dependencies, packageName = ProcessorConfig.GENERATED_PACKAGE, fileName = fileName, ) - PrintWriter(file, true, StandardCharsets.UTF_8).use { writer -> writeGeneratedCode(writer, context) } @@ -197,14 +176,11 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val private fun writeGeneratedCode(writer: PrintWriter, context: GenerationContext) { writeFileHeader(writer, context.classDecl, context.injectionContext.contextType) - val constructorParams = writeImportsAndFunction(writer, context) - val hasNode = context.injectionContext.indices.containsKey(InjectionType.NODE) && context.injectionContext.annotationValues["injectNode"] as? Boolean ?: true val hasReaction = context.injectionContext.indices.containsKey(InjectionType.REACTION) && context.injectionContext.annotationValues["injectReaction"] as? Boolean ?: true - if (hasNode && !hasReaction) { writePropertyContextFunction(writer, context, constructorParams) } @@ -215,9 +191,10 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val writer.println("package ${ProcessorConfig.GENERATED_PACKAGE}") writer.println() writer.println("import ${classDecl.qualifiedName?.asString()}") - when (contextType) { - ContextType.SIMULATION -> writer.println("import ${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}") + ContextType.SIMULATION_CONTEXT -> writer.println( + "import ${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}", + ) ContextType.EXPORTER_CONTEXT -> writer.println("import ${ProcessorConfig.ContextTypes.EXPORTER_CONTEXT}") ContextType.GLOBAL_PROGRAMS_CONTEXT -> writer.println( "import ${ProcessorConfig.ContextTypes.GLOBAL_PROGRAMS_CONTEXT}", @@ -228,15 +205,17 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val ContextType.TERMINATORS_CONTEXT -> writer.println( "import ${ProcessorConfig.ContextTypes.TERMINATORS_CONTEXT}", ) - ContextType.DEPLOYMENT -> writer.println("import ${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}") + ContextType.DEPLOYMENTS_CONTEXT -> writer.println( + "import ${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}", + ) ContextType.DEPLOYMENT_CONTEXT -> writer.println( "import ${ProcessorConfig.ContextTypes.DEPLOYMENT_CONTEXT}", ) - ContextType.PROGRAM -> { + ContextType.PROGRAM_CONTEXT -> { writer.println("import ${ProcessorConfig.ContextTypes.PROGRAM_CONTEXT}") writer.println("import ${ProcessorConfig.ContextTypes.PROPERTIES_CONTEXT}") } - ContextType.PROPERTY -> { + ContextType.PROPERTY_CONTEXT -> { writer.println("import ${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}") } } @@ -274,7 +253,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val val injectedParams = mutableListOf>() val injectedParamNames = mutableMapOf() val injectedParamTypesMap = mutableMapOf() - injectionIndices.forEach { (injectionType, index) -> if (shouldInjectType(injectionType, annotationValues)) { val param = allParameters[index] @@ -285,7 +263,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val injectedParamTypesMap[injectionType] = paramType } } - return Triple(injectedParams, injectedParamNames, injectedParamTypesMap) } @@ -312,9 +289,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val if (!hasInjectedParams) { return } - val newTypeParams = mutableMapOf() - injectionIndices.forEach { (injectionType, index) -> if (shouldInjectType(injectionType, annotationValues)) { val param = allParameters[index] @@ -330,16 +305,12 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val } } } - val originalTypeParams = initialTypeParamNames.toSet() val allNewParams = typeParamNames.filter { it !in originalTypeParams } - typeParamNames.clear() typeParamBounds.clear() - typeParamNames.addAll(initialTypeParamNames) typeParamBounds.addAll(initialTypeParamBounds) - allNewParams.forEach { param -> if (!typeParamNames.contains(param)) { typeParamNames.add(param) @@ -393,13 +364,11 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val context.needsMapEnvironment, context.injectionContext.paramTypes.values.toList(), ) - val constructorParams = FunctionGenerator.buildConstructorParams( context.constructorInfo, context.injectionContext, context.typeParams.names, ) - val functionSignature = FunctionGenerator.buildFunctionSignature( context.functionName, context.className, @@ -408,7 +377,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val context.injectedParams, context.injectionContext.contextType, ) - writer.println(functionSignature) val constructorCall = FunctionGenerator.buildConstructorCall( context.className, @@ -426,14 +394,12 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val @Suppress("UNUSED_PARAMETER") constructorParams: List, ) { writer.println() - val (tParam, pParam) = TypeParameterHandler.findTAndPParams( context.typeParams.names, context.typeParams.bounds, ) val pVariance = FunctionGenerator.extractVarianceFromBound(pParam, context.typeParams.bounds) val pWithVariance = if (pVariance.isNotEmpty()) "$pVariance $pParam" else pParam - val functionTypeParamString = TypeParameterHandler.buildTypeParamString(context.typeParams.bounds) val returnType = TypeParameterHandler.buildReturnType( context.className, @@ -445,11 +411,9 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val context.constructorInfo.paramNames, context.constructorInfo.paramTypes, ) - val functionSignature = "${contextPart}fun$functionTypeParamString " + "${context.functionName}$functionParams: $returnType =" writer.println(functionSignature) - val propertyContextConstructorParams = ConstructorParamBuilder.convertToPropertyContextAccessors( context.constructorInfo, context.injectionContext, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt index 0d64478f7f..2470144140 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt @@ -28,10 +28,10 @@ object FunctionGenerator { constructorInfo.paramTypes, ) val receiverPart = buildReceiverPart(injectedParams, contextType) - return "${contextPart}fun$functionTypeParamString $receiverPart$functionName$functionParams: $returnType =" } + // Build the context receiver only when injections exist. private fun buildContextPart( injectedParams: List>, contextType: ContextType, @@ -41,28 +41,26 @@ object FunctionGenerator { if (injectedParams.isEmpty()) { return "" } - val (tParam, pParam) = TypeParameterHandler.findTAndPParams(typeParamNames, typeParamBounds) val pVariance = extractVarianceFromBound(pParam, typeParamBounds) - val tWithVariance = tParam val pWithVariance = if (pVariance.isNotEmpty()) "$pVariance $pParam" else pParam val contextTypeName = when (contextType) { - ContextType.SIMULATION -> - "${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}<$tWithVariance, $pWithVariance>" + ContextType.SIMULATION_CONTEXT -> + "${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}<$tParam, $pWithVariance>" ContextType.EXPORTER_CONTEXT -> - "${ProcessorConfig.ContextTypes.EXPORTER_CONTEXT}<$tWithVariance, $pWithVariance>" + "${ProcessorConfig.ContextTypes.EXPORTER_CONTEXT}<$tParam, $pWithVariance>" ContextType.GLOBAL_PROGRAMS_CONTEXT -> - "${ProcessorConfig.ContextTypes.GLOBAL_PROGRAMS_CONTEXT}<$tWithVariance, $pWithVariance>" + "${ProcessorConfig.ContextTypes.GLOBAL_PROGRAMS_CONTEXT}<$tParam, $pWithVariance>" ContextType.OUTPUT_MONITORS_CONTEXT -> - "${ProcessorConfig.ContextTypes.OUTPUT_MONITORS_CONTEXT}<$tWithVariance, $pWithVariance>" + "${ProcessorConfig.ContextTypes.OUTPUT_MONITORS_CONTEXT}<$tParam, $pWithVariance>" ContextType.TERMINATORS_CONTEXT -> - "${ProcessorConfig.ContextTypes.TERMINATORS_CONTEXT}<$tWithVariance, $pWithVariance>" - ContextType.DEPLOYMENT -> - "${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}<$tWithVariance, $pWithVariance>" + "${ProcessorConfig.ContextTypes.TERMINATORS_CONTEXT}<$tParam, $pWithVariance>" + ContextType.DEPLOYMENTS_CONTEXT -> + "${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}<$tParam, $pWithVariance>" ContextType.DEPLOYMENT_CONTEXT -> - "${ProcessorConfig.ContextTypes.DEPLOYMENT_CONTEXT}<$tWithVariance, $pWithVariance>" - ContextType.PROGRAM -> "${ProcessorConfig.ContextTypes.PROGRAM_CONTEXT}<$tWithVariance, $pWithVariance>" - ContextType.PROPERTY -> "${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}<$tWithVariance, $pWithVariance>" + "${ProcessorConfig.ContextTypes.DEPLOYMENT_CONTEXT}<$tParam, $pWithVariance>" + ContextType.PROGRAM_CONTEXT -> "${ProcessorConfig.ContextTypes.PROGRAM_CONTEXT}<$tParam, $pWithVariance>" + ContextType.PROPERTY_CONTEXT -> "${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}<$tParam, $pWithVariance>" } return "context(ctx: $contextTypeName) " } @@ -74,7 +72,6 @@ object FunctionGenerator { } val bound = typeParamBounds[paramIndex] val boundPart = bound.substringAfter(":", "").trim() - return extractVarianceFromBoundPart(paramName, boundPart) } @@ -82,7 +79,6 @@ object FunctionGenerator { val escapedParamName = Regex.escape(paramName) val outPattern = Regex("""""") val inPattern = Regex("""""") - return when { outPattern.containsMatchIn(boundPart) || boundPart.startsWith("out ") -> "out" inPattern.containsMatchIn(boundPart) || boundPart.startsWith("in ") -> "in" @@ -102,7 +98,6 @@ object FunctionGenerator { val defaultValue = extractDefaultValue(param) "$varargKeyword$name: $type$defaultValue" } - val regularParamsPart = regularParams.joinToString(", ") return if (regularParamsPart.isEmpty()) { "()" @@ -112,7 +107,6 @@ object FunctionGenerator { } private const val EMPTY_RECEIVER = "" - private fun buildReceiverPart( @Suppress("UNUSED_PARAMETER") injectedParams: List>, @Suppress("UNUSED_PARAMETER") contextType: ContextType, @@ -146,7 +140,6 @@ object FunctionGenerator { if (!param.hasDefault) { return "" } - val defaultValueExpr = DefaultValueAnalyzer.tryExtractDefaultFromSource(param) return defaultValueExpr?.let { " = $it" }.orEmpty() } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt index dce4cdbc00..504506ac5a 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt @@ -1,7 +1,6 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSValueParameter import java.io.PrintWriter /** @@ -30,7 +29,6 @@ object ImportManager { ) { val neededImports = DefaultValueAnalyzer.extractNeededImportsFromDefaults(defaultValues, classDecl) neededImports.forEach { writer.println(it) } - writer.println() } } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index 2e21e703a7..75f7e8afcb 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -1,5 +1,6 @@ package it.unibo.alchemist.boundary.dsl.processor +import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSValueParameter /** @@ -56,29 +57,26 @@ object ParameterInjector { */ fun findInjectionIndices(parameters: List): Map { val indices = mutableMapOf() - parameters.forEachIndexed { index, param -> val resolved = param.type.resolve() val declaration = resolved.declaration val qualifiedName = declaration.qualifiedName?.asString().orEmpty() val simpleName = declaration.simpleName.asString() - when { isEnvironmentType(resolved, qualifiedName) -> indices[InjectionType.ENVIRONMENT] = index isGeneratorType(resolved, qualifiedName) -> indices[InjectionType.GENERATOR] = index isIncarnationType(resolved, qualifiedName) -> indices[InjectionType.INCARNATION] = index isNodeType(resolved, simpleName, qualifiedName) -> indices[InjectionType.NODE] = index isReactionType(resolved, simpleName, qualifiedName) -> indices[InjectionType.REACTION] = index - isTimeDistributionType(resolved, simpleName, qualifiedName) -> indices[InjectionType.TIMEDISTRIBUTION] = - index + isTimeDistributionType(resolved, simpleName, qualifiedName) -> + indices[InjectionType.TIMEDISTRIBUTION] = index isFilterType(resolved, simpleName, qualifiedName) -> indices[InjectionType.FILTER] = index } } - return indices } - private fun isEnvironmentType(type: com.google.devtools.ksp.symbol.KSType, qualifiedName: String): Boolean { + private fun isEnvironmentType(type: KSType, qualifiedName: String): Boolean { if (!qualifiedName.contains("Environment")) { return false } @@ -89,7 +87,7 @@ object ParameterInjector { ) } - private fun isGeneratorType(type: com.google.devtools.ksp.symbol.KSType, qualifiedName: String): Boolean { + private fun isGeneratorType(type: KSType, qualifiedName: String): Boolean { if (!qualifiedName.contains("RandomGenerator")) { return false } @@ -97,7 +95,7 @@ object ParameterInjector { qualifiedName == ProcessorConfig.RANDOM_GENERATOR_TYPE } - private fun isIncarnationType(type: com.google.devtools.ksp.symbol.KSType, qualifiedName: String): Boolean { + private fun isIncarnationType(type: KSType, qualifiedName: String): Boolean { if (!qualifiedName.contains("Incarnation")) { return false } @@ -105,11 +103,7 @@ object ParameterInjector { qualifiedName == ProcessorConfig.INCARNATION_TYPE } - private fun isNodeType( - type: com.google.devtools.ksp.symbol.KSType, - simpleName: String, - qualifiedName: String, - ): Boolean { + private fun isNodeType(type: KSType, simpleName: String, qualifiedName: String): Boolean { if (simpleName != "Node" && !qualifiedName.endsWith(".Node")) { return false } @@ -118,11 +112,7 @@ object ParameterInjector { qualifiedName.startsWith("${ProcessorConfig.NODE_TYPE}.") } - private fun isReactionType( - type: com.google.devtools.ksp.symbol.KSType, - simpleName: String, - qualifiedName: String, - ): Boolean { + private fun isReactionType(type: KSType, simpleName: String, qualifiedName: String): Boolean { if (simpleName != "Reaction" && !qualifiedName.endsWith(".Reaction")) { return false } @@ -131,11 +121,7 @@ object ParameterInjector { qualifiedName.startsWith("${ProcessorConfig.REACTION_TYPE}.") } - private fun isTimeDistributionType( - type: com.google.devtools.ksp.symbol.KSType, - simpleName: String, - qualifiedName: String, - ): Boolean { + private fun isTimeDistributionType(type: KSType, simpleName: String, qualifiedName: String): Boolean { if (simpleName != "TimeDistribution" && !qualifiedName.endsWith(".TimeDistribution")) { return false } @@ -144,16 +130,11 @@ object ParameterInjector { qualifiedName.startsWith("${ProcessorConfig.TIME_DISTRIBUTION_TYPE}.") } - private fun isFilterType( - type: com.google.devtools.ksp.symbol.KSType, - simpleName: String, - qualifiedName: String, - ): Boolean { + private fun isFilterType(type: KSType, simpleName: String, qualifiedName: String): Boolean { val effectiveType = type.makeNotNullable() val effectiveDeclaration = effectiveType.declaration val effectiveQualifiedName = effectiveDeclaration.qualifiedName?.asString().orEmpty() val effectiveSimpleName = effectiveDeclaration.simpleName.asString() - if (effectiveSimpleName != "PositionBasedFilter" && !effectiveQualifiedName.endsWith(".PositionBasedFilter")) { return false } @@ -173,18 +154,17 @@ object ParameterInjector { if (scope.isNullOrBlank()) { return null } - val upperScope = scope.uppercase() - - return when (upperScope) { - "SIMULATION", "SIMULATION_CONTEXT" -> ContextType.SIMULATION + // accept both versions or the scope + return when (val upperScope = scope.uppercase()) { + "SIMULATION", "SIMULATION_CONTEXT" -> ContextType.SIMULATION_CONTEXT "EXPORTER", "EXPORTER_CONTEXT" -> ContextType.EXPORTER_CONTEXT "GLOBAL_PROGRAMS", "GLOBAL_PROGRAMS_CONTEXT" -> ContextType.GLOBAL_PROGRAMS_CONTEXT "OUTPUT_MONITORS", "OUTPUT_MONITORS_CONTEXT" -> ContextType.OUTPUT_MONITORS_CONTEXT "TERMINATORS", "TERMINATORS_CONTEXT" -> ContextType.TERMINATORS_CONTEXT - "DEPLOYMENT", "DEPLOYMENTS_CONTEXT" -> ContextType.DEPLOYMENT + "DEPLOYMENT", "DEPLOYMENTS_CONTEXT" -> ContextType.DEPLOYMENTS_CONTEXT "DEPLOYMENT_CONTEXT" -> ContextType.DEPLOYMENT_CONTEXT - "PROGRAM", "PROGRAM_CONTEXT" -> ContextType.PROGRAM - "PROPERTY", "PROPERTY_CONTEXT" -> ContextType.PROPERTY + "PROGRAM", "PROGRAM_CONTEXT" -> ContextType.PROGRAM_CONTEXT + "PROPERTY", "PROPERTY_CONTEXT" -> ContextType.PROPERTY_CONTEXT else -> { @Suppress("SwallowedException") try { @@ -204,6 +184,7 @@ object ParameterInjector { * @param annotationValues Annotation values from the BuildDsl annotation * @return The determined context type */ + // Determine which context is active by checking manual overrides first, then injection mix. fun determineContextType( injectionIndices: Map, annotationValues: Map, @@ -215,7 +196,6 @@ object ParameterInjector { return parsedScope } } - return determineContextTypeFromInjections(injectionIndices, annotationValues) } @@ -224,7 +204,7 @@ object ParameterInjector { annotationValues: Map, ): ContextType = when { injectionIndices.containsKey(InjectionType.FILTER) -> ContextType.DEPLOYMENT_CONTEXT - hasProgramContextInjections(injectionIndices, annotationValues) -> ContextType.PROGRAM + hasProgramContextInjections(injectionIndices, annotationValues) -> ContextType.PROGRAM_CONTEXT else -> determineDeploymentOrSimulationContext(injectionIndices, annotationValues) } @@ -250,13 +230,11 @@ object ParameterInjector { annotationValues["injectGenerator"] as? Boolean ?: true val hasIncarnation = injectionIndices.containsKey(InjectionType.INCARNATION) && annotationValues["injectIncarnation"] as? Boolean ?: true - val injectedCount = listOf(hasEnvironment, hasGenerator, hasIncarnation).count { it } - return if (injectedCount == 1 && (hasIncarnation || hasEnvironment)) { - ContextType.SIMULATION + ContextType.SIMULATION_CONTEXT } else { - ContextType.DEPLOYMENT + ContextType.DEPLOYMENTS_CONTEXT } } @@ -274,7 +252,6 @@ object ParameterInjector { contextType: ContextType, ): Set { val paramsToSkip = mutableSetOf() - if (isInjectionTypeAvailable(InjectionType.ENVIRONMENT, contextType)) { addInjectionParamIfEnabled( InjectionType.ENVIRONMENT, @@ -324,15 +301,12 @@ object ParameterInjector { paramsToSkip, ) } - if (isInjectionTypeAvailable(InjectionType.TIMEDISTRIBUTION, contextType)) { injectionIndices[InjectionType.TIMEDISTRIBUTION]?.let { paramsToSkip.add(it) } } - if (isInjectionTypeAvailable(InjectionType.FILTER, contextType)) { injectionIndices[InjectionType.FILTER]?.let { paramsToSkip.add(it) } } - return paramsToSkip } @@ -364,7 +338,7 @@ object ParameterInjector { */ enum class ContextType { /** Simulation context (only incarnation or only environment). */ - SIMULATION, + SIMULATION_CONTEXT, /** Exporter context (one level below SimulationContext, manually settable). */ EXPORTER_CONTEXT, @@ -378,15 +352,15 @@ enum class ContextType { /** Terminators context (one level below SimulationContext, manually settable). */ TERMINATORS_CONTEXT, - /** Deployments context (environment and generator). */ - DEPLOYMENT, + /** Deployments context (generator). */ + DEPLOYMENTS_CONTEXT, /** Deployment context (singular, one level below DeploymentsContext, includes filter). */ DEPLOYMENT_CONTEXT, /** Program context (includes node, reaction, and time distribution). */ - PROGRAM, + PROGRAM_CONTEXT, /** Property context (includes node, same depth as program context). */ - PROPERTY, + PROPERTY_CONTEXT, } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt index 2f0e37fe09..64b3194104 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt @@ -119,6 +119,7 @@ object ProcessorConfig { * @param qualifiedName The fully qualified name to check * @return True if the name matches an environment package pattern */ + // Provide centralized patterns instead of ad-hoc string checks so injector stays flexible. fun isEnvironmentPackage(qualifiedName: String): Boolean = ENVIRONMENT_PACKAGE_PATTERNS.any { pattern -> qualifiedName.startsWith(pattern) } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt index 4a80d2a5e0..ad0a87b40e 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt @@ -1,6 +1,12 @@ package it.unibo.alchemist.boundary.dsl.processor +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSDeclaration +import com.google.devtools.ksp.symbol.KSTypeAlias +import com.google.devtools.ksp.symbol.KSTypeArgument +import com.google.devtools.ksp.symbol.KSTypeParameter import com.google.devtools.ksp.symbol.KSTypeReference +import com.google.devtools.ksp.symbol.Variance /** * Processes type arguments for context parameters in DSL builder functions. @@ -23,15 +29,13 @@ object TypeArgumentProcessor { val declaration = resolved.declaration val typeName = getTypeName(declaration) val arguments = resolved.arguments - if (arguments.isEmpty()) { return typeName } - val declarationTypeParams = getDeclarationTypeParams(declaration) - val standardTypeParams = listOf("T", "U", "V", "W", "X", "Y", "Z") + // These are fallback names for wildcard/null arguments so we always generate valid type parameters. + val standardTypeParams = listOf("T", "U", "V", "W") val indexState = IndexState(0, 0) - val typeArgs = arguments.joinToString(", ") { arg -> processTypeArgument( arg, @@ -48,7 +52,7 @@ object TypeArgumentProcessor { private data class IndexState(var nextStandardIndex: Int, var nextDeclParamIndex: Int) - private fun getTypeName(declaration: com.google.devtools.ksp.symbol.KSDeclaration): String { + private fun getTypeName(declaration: KSDeclaration): String { val qualifiedName = declaration.qualifiedName?.asString() return if (qualifiedName != null && qualifiedName.isNotEmpty()) { qualifiedName @@ -57,23 +61,21 @@ object TypeArgumentProcessor { } } - private fun getDeclarationTypeParams( - declaration: com.google.devtools.ksp.symbol.KSDeclaration, - ): List = when (declaration) { - is com.google.devtools.ksp.symbol.KSClassDeclaration -> declaration.typeParameters - is com.google.devtools.ksp.symbol.KSTypeAlias -> declaration.typeParameters + private fun getDeclarationTypeParams(declaration: KSDeclaration): List = when (declaration) { + is KSClassDeclaration -> declaration.typeParameters + is KSTypeAlias -> declaration.typeParameters else -> emptyList() } private fun processTypeArgument( - arg: com.google.devtools.ksp.symbol.KSTypeArgument, - declarationTypeParams: List, + arg: KSTypeArgument, + declarationTypeParams: List, standardTypeParams: List, typeParamNames: MutableList, typeParamBounds: MutableList, indexState: IndexState, ): String = when { - arg.type == null || arg.variance == com.google.devtools.ksp.symbol.Variance.STAR -> { + arg.type == null || arg.variance == Variance.STAR -> { val result = handleNullOrStarTypeArg( declarationTypeParams, standardTypeParams, @@ -90,7 +92,7 @@ object TypeArgumentProcessor { } private fun handleNullOrStarTypeArg( - declarationTypeParams: List, + declarationTypeParams: List, standardTypeParams: List, typeParamNames: MutableList, typeParamBounds: MutableList, @@ -105,13 +107,11 @@ object TypeArgumentProcessor { } else { "T" to null } - val newNextDeclParamIndex = if (nextDeclParamIndex < declarationTypeParams.size) { nextDeclParamIndex + 1 } else { nextDeclParamIndex } - val newNextStandardIndex = if (nextDeclParamIndex >= declarationTypeParams.size && nextStandardIndex < standardTypeParams.size ) { @@ -119,7 +119,6 @@ object TypeArgumentProcessor { } else { nextStandardIndex } - if (!typeParamNames.contains(paramName)) { typeParamNames.add(paramName) val boundStr = if (declParam != null) { @@ -136,12 +135,11 @@ object TypeArgumentProcessor { } typeParamBounds.add(boundStr) } - return Triple(paramName, newNextDeclParamIndex, newNextStandardIndex) } private fun processConcreteTypeArgument( - arg: com.google.devtools.ksp.symbol.KSTypeArgument, + arg: KSTypeArgument, typeParamNames: MutableList, typeParamBounds: MutableList, standardTypeParams: List, @@ -149,7 +147,7 @@ object TypeArgumentProcessor { ): String { val argType = arg.type ?: return "T" val argDecl = argType.resolve().declaration - return if (argDecl is com.google.devtools.ksp.symbol.KSTypeParameter) { + return if (argDecl is KSTypeParameter) { addTypeParameterIfNeeded(argDecl, typeParamNames, typeParamBounds) argDecl.name.asString() } else { @@ -158,7 +156,7 @@ object TypeArgumentProcessor { } private fun addTypeParameterIfNeeded( - argDecl: com.google.devtools.ksp.symbol.KSTypeParameter, + argDecl: KSTypeParameter, typeParamNames: MutableList, typeParamBounds: MutableList, ) { diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt index 6dd76a9e7e..b8fed31cc4 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt @@ -42,17 +42,16 @@ object TypeExtractor { * @param typeParamNames List of existing type parameter names for substitution * @return A string representation of the type */ + // Normalize a KSTypeReference into a printable string, respecting existing type parameter names. fun extractTypeString(typeRef: KSTypeReference, typeParamNames: List = emptyList()): String { val resolved = typeRef.resolve() val declaration = resolved.declaration - if (declaration is KSTypeParameter) { val paramName = declaration.name.asString() if (typeParamNames.contains(paramName)) { return paramName } } - val typeName = getTypeName(declaration) val arguments = resolved.arguments val typeString = if (arguments.isNotEmpty()) { @@ -63,7 +62,6 @@ object TypeExtractor { } else { typeName } - return if (resolved.isMarkedNullable) { "$typeString?" } else { @@ -80,6 +78,7 @@ object TypeExtractor { } } + // Represent the variance and nested references for each argument. private fun formatTypeArgument(arg: KSTypeArgument, typeParamNames: List): String = when { arg.type == null -> "*" arg.variance == Variance.STAR -> "*" diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt index f0a88ec813..4640db0806 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt @@ -19,11 +19,9 @@ object TypeHierarchyChecker { fun isAssignableTo(type: KSType, targetQualifiedName: String): Boolean { val declaration = type.declaration val typeQualifiedName = declaration.qualifiedName?.asString() - if (typeQualifiedName == targetQualifiedName) { return true } - return declaration is KSClassDeclaration && checkSuperTypes(declaration, targetQualifiedName, mutableSetOf()) } @@ -48,10 +46,9 @@ object TypeHierarchyChecker { visited: MutableSet, ): Boolean { val qualifiedName = classDecl.qualifiedName?.asString() ?: return false - - return when { - qualifiedName in visited -> false - qualifiedName == targetQualifiedName -> true + return when (qualifiedName) { + in visited -> false + targetQualifiedName -> true else -> { visited.add(qualifiedName) checkSuperTypesRecursive(classDecl, targetQualifiedName, visited) @@ -81,7 +78,6 @@ object TypeHierarchyChecker { ): Boolean = try { val resolved = superType.resolve() val superDecl = resolved.declaration - val superQualifiedName = superDecl.qualifiedName?.asString() superQualifiedName == targetQualifiedName || (superDecl is KSClassDeclaration && checkSuperTypes(superDecl, targetQualifiedName, visited)) @@ -97,10 +93,10 @@ object TypeHierarchyChecker { * @param targetQualifiedNames Set of fully qualified names to match against * @return True if the type matches any target name */ + // Walk the inheritance tree to check for supertypes without relying on string heuristics. fun matchesAny(type: KSType, targetQualifiedNames: Set): Boolean { val declaration = type.declaration val qualifiedName = declaration.qualifiedName?.asString() ?: return false - return targetQualifiedNames.contains(qualifiedName) || targetQualifiedNames.any { targetName -> isAssignableTo(type, targetName) } } @@ -116,7 +112,6 @@ object TypeHierarchyChecker { fun matchesTypeOrPackage(type: KSType, targetQualifiedName: String, packagePatterns: Set): Boolean { val declaration = type.declaration val qualifiedName = declaration.qualifiedName?.asString() ?: return false - return qualifiedName == targetQualifiedName || isAssignableTo(type, targetQualifiedName) || packagePatterns.any { pattern -> qualifiedName.startsWith(pattern) } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt index d195cf13a6..6328f9f463 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt @@ -26,7 +26,6 @@ object TypeParameterHandler { ): Pair, MutableList> { val finalTypeParamNames = typeParamNames.toMutableList() val finalTypeParamBounds = typeParamBounds.toMutableList() - if (injectedParams.isNotEmpty()) { val (tParam, pParam) = findTAndPParams(typeParamNames, typeParamBounds) addTParamIfNeeded(tParam, finalTypeParamNames, finalTypeParamBounds) @@ -40,7 +39,6 @@ object TypeParameterHandler { finalTypeParamBounds.add(bound) } } - return finalTypeParamNames to finalTypeParamBounds } @@ -105,13 +103,11 @@ object TypeParameterHandler { */ fun findTAndPParams(typeParamNames: List, typeParamBounds: List): Pair { val pIndex = typeParamBounds.indexOfFirst { it.contains("Position") } - val pParam = if (pIndex >= 0 && pIndex < typeParamNames.size) { typeParamNames[pIndex] } else { "P" } - val tIndex = typeParamNames.indexOf("T") val tParam = when { tIndex >= 0 -> typeParamNames[tIndex] @@ -120,7 +116,6 @@ object TypeParameterHandler { typeParamNames.isNotEmpty() && pIndex < 0 -> typeParamNames[0] else -> "T" } - return tParam to pParam } @@ -161,11 +156,9 @@ object TypeParameterHandler { val needed = mutableSetOf() val resolved = typeRef.resolve() val arguments = resolved.arguments - arguments.forEach { arg -> processTypeArgForCollection(arg, existingTypeParamNames, needed) } - return needed } diff --git a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt index 659bee8ae0..05a4f417f4 100644 --- a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt +++ b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt @@ -15,12 +15,18 @@ import org.junit.jupiter.api.Test class ContextAccessorTest { @Test fun `test simulation context accessors`() { - assertEquals("ctx.environment", ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.SIMULATION)) + assertEquals( + "ctx.environment", + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.SIMULATION_CONTEXT), + ) assertEquals( "ctx.scenarioGenerator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.SIMULATION), + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.SIMULATION_CONTEXT), + ) + assertEquals( + "ctx.incarnation", + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.SIMULATION_CONTEXT), ) - assertEquals("ctx.incarnation", ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.SIMULATION)) } @Test @@ -91,12 +97,15 @@ class ContextAccessorTest { fun `test deployment context accessors`() { assertEquals( "ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT), + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENTS_CONTEXT), + ) + assertEquals( + "ctx.generator", + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.DEPLOYMENTS_CONTEXT), ) - assertEquals("ctx.generator", ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.DEPLOYMENT)) assertEquals( "ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.DEPLOYMENT), + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.DEPLOYMENTS_CONTEXT), ) } @@ -121,21 +130,21 @@ class ContextAccessorTest { fun `test program context accessors`() { assertEquals( "ctx.ctx.ctx.ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROGRAM), + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROGRAM_CONTEXT), ) assertEquals( "ctx.ctx.ctx.ctx.generator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROGRAM), + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROGRAM_CONTEXT), ) assertEquals( "ctx.ctx.ctx.ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.PROGRAM), + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.PROGRAM_CONTEXT), ) - assertEquals("ctx.node", ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROGRAM)) - assertEquals("ctx.reaction", ContextAccessor.getAccessor(InjectionType.REACTION, ContextType.PROGRAM)) + assertEquals("ctx.node", ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROGRAM_CONTEXT)) + assertEquals("ctx.reaction", ContextAccessor.getAccessor(InjectionType.REACTION, ContextType.PROGRAM_CONTEXT)) assertEquals( "ctx.timeDistribution!!", - ContextAccessor.getAccessor(InjectionType.TIMEDISTRIBUTION, ContextType.PROGRAM), + ContextAccessor.getAccessor(InjectionType.TIMEDISTRIBUTION, ContextType.PROGRAM_CONTEXT), ) } @@ -143,28 +152,28 @@ class ContextAccessorTest { fun `test property context accessors`() { assertEquals( "ctx.ctx.ctx.ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROPERTY), + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROPERTY_CONTEXT), ) assertEquals( "ctx.ctx.ctx.ctx.generator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROPERTY), + ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROPERTY_CONTEXT), ) assertEquals( "ctx.ctx.ctx.ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.PROPERTY), + ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.PROPERTY_CONTEXT), ) - assertEquals("ctx.node", ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROPERTY)) + assertEquals("ctx.node", ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROPERTY_CONTEXT)) } @Test fun `test custom context parameter name`() { assertEquals( "customCtx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT, "customCtx"), + ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENTS_CONTEXT, "customCtx"), ) assertEquals( "customCtx.node", - ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROGRAM, "customCtx"), + ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROGRAM_CONTEXT, "customCtx"), ) } } diff --git a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt index 7b0f19f299..a279497e74 100644 --- a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt +++ b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt @@ -1,7 +1,6 @@ package it.unibo.alchemist.boundary.dsl.processor import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test class ParameterInjectorTest { @@ -15,7 +14,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.PROGRAM, contextType) + assertEquals(ContextType.PROGRAM_CONTEXT, contextType) } @Test @@ -27,7 +26,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.SIMULATION, contextType) + assertEquals(ContextType.SIMULATION_CONTEXT, contextType) } @Test @@ -39,7 +38,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.SIMULATION, contextType) + assertEquals(ContextType.SIMULATION_CONTEXT, contextType) } @Test @@ -52,7 +51,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.DEPLOYMENT, contextType) + assertEquals(ContextType.DEPLOYMENTS_CONTEXT, contextType) } @Test @@ -64,7 +63,11 @@ class ParameterInjectorTest { ) val annotationValues = emptyMap() - val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues, ContextType.PROGRAM) + val paramsToSkip = ParameterInjector.getInjectionParams( + injectionIndices, + annotationValues, + ContextType.PROGRAM_CONTEXT, + ) assertEquals(setOf(0, 1, 2), paramsToSkip) } @@ -80,7 +83,7 @@ class ParameterInjectorTest { val paramsToSkip = ParameterInjector.getInjectionParams( injectionIndices, annotationValues, - ContextType.DEPLOYMENT, + ContextType.DEPLOYMENTS_CONTEXT, ) assertEquals(setOf(1), paramsToSkip) @@ -93,7 +96,11 @@ class ParameterInjectorTest { ) val annotationValues = emptyMap() - val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues, ContextType.PROGRAM) + val paramsToSkip = ParameterInjector.getInjectionParams( + injectionIndices, + annotationValues, + ContextType.PROGRAM_CONTEXT, + ) assertEquals(setOf(0), paramsToSkip) } @@ -124,7 +131,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.PROGRAM, contextType) + assertEquals(ContextType.PROGRAM_CONTEXT, contextType) } @Test @@ -137,7 +144,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.SIMULATION, contextType) + assertEquals(ContextType.SIMULATION_CONTEXT, contextType) } @Test @@ -149,7 +156,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.DEPLOYMENT, contextType) + assertEquals(ContextType.DEPLOYMENTS_CONTEXT, contextType) } @Test @@ -161,7 +168,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.DEPLOYMENT, contextType) + assertEquals(ContextType.DEPLOYMENTS_CONTEXT, contextType) } @Test @@ -173,7 +180,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.PROPERTY, contextType) + assertEquals(ContextType.PROPERTY_CONTEXT, contextType) } @Test @@ -198,7 +205,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.PROGRAM, contextType) + assertEquals(ContextType.PROGRAM_CONTEXT, contextType) } @Test @@ -258,7 +265,7 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.SIMULATION, contextType) + assertEquals(ContextType.SIMULATION_CONTEXT, contextType) } @Test @@ -270,14 +277,14 @@ class ParameterInjectorTest { val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - assertEquals(ContextType.SIMULATION, contextType) + assertEquals(ContextType.SIMULATION_CONTEXT, contextType) } @Test fun `test parseScope with valid values`() { - assertEquals(ContextType.PROGRAM, ParameterInjector.parseScope("PROGRAM")) - assertEquals(ContextType.SIMULATION, ParameterInjector.parseScope("SIMULATION")) - assertEquals(ContextType.SIMULATION, ParameterInjector.parseScope("SIMULATION_CONTEXT")) + assertEquals(ContextType.PROGRAM_CONTEXT, ParameterInjector.parseScope("PROGRAM")) + assertEquals(ContextType.SIMULATION_CONTEXT, ParameterInjector.parseScope("SIMULATION")) + assertEquals(ContextType.SIMULATION_CONTEXT, ParameterInjector.parseScope("SIMULATION_CONTEXT")) assertEquals(ContextType.EXPORTER_CONTEXT, ParameterInjector.parseScope("EXPORTER")) assertEquals(ContextType.EXPORTER_CONTEXT, ParameterInjector.parseScope("EXPORTER_CONTEXT")) assertEquals(ContextType.GLOBAL_PROGRAMS_CONTEXT, ParameterInjector.parseScope("GLOBAL_PROGRAMS")) @@ -286,15 +293,15 @@ class ParameterInjectorTest { assertEquals(ContextType.OUTPUT_MONITORS_CONTEXT, ParameterInjector.parseScope("OUTPUT_MONITORS_CONTEXT")) assertEquals(ContextType.TERMINATORS_CONTEXT, ParameterInjector.parseScope("TERMINATORS")) assertEquals(ContextType.TERMINATORS_CONTEXT, ParameterInjector.parseScope("TERMINATORS_CONTEXT")) - assertEquals(ContextType.DEPLOYMENT, ParameterInjector.parseScope("DEPLOYMENT")) - assertEquals(ContextType.DEPLOYMENT, ParameterInjector.parseScope("DEPLOYMENTS_CONTEXT")) + assertEquals(ContextType.DEPLOYMENTS_CONTEXT, ParameterInjector.parseScope("DEPLOYMENT")) + assertEquals(ContextType.DEPLOYMENTS_CONTEXT, ParameterInjector.parseScope("DEPLOYMENTS_CONTEXT")) assertEquals(ContextType.DEPLOYMENT_CONTEXT, ParameterInjector.parseScope("DEPLOYMENT_CONTEXT")) - assertEquals(ContextType.PROPERTY, ParameterInjector.parseScope("PROPERTY")) - assertEquals(ContextType.PROPERTY, ParameterInjector.parseScope("PROPERTY_CONTEXT")) - assertEquals(ContextType.PROGRAM, ParameterInjector.parseScope("PROGRAM_CONTEXT")) - assertEquals(ContextType.PROGRAM, ParameterInjector.parseScope("program")) - assertEquals(ContextType.SIMULATION, ParameterInjector.parseScope("simulation")) - assertEquals(ContextType.DEPLOYMENT, ParameterInjector.parseScope("deployments_context")) + assertEquals(ContextType.PROPERTY_CONTEXT, ParameterInjector.parseScope("PROPERTY")) + assertEquals(ContextType.PROPERTY_CONTEXT, ParameterInjector.parseScope("PROPERTY_CONTEXT")) + assertEquals(ContextType.PROGRAM_CONTEXT, ParameterInjector.parseScope("PROGRAM_CONTEXT")) + assertEquals(ContextType.PROGRAM_CONTEXT, ParameterInjector.parseScope("program")) + assertEquals(ContextType.SIMULATION_CONTEXT, ParameterInjector.parseScope("simulation")) + assertEquals(ContextType.DEPLOYMENTS_CONTEXT, ParameterInjector.parseScope("deployments_context")) assertEquals(ContextType.EXPORTER_CONTEXT, ParameterInjector.parseScope("exporter")) } From ba61b9aff3ec32f033f71675b1c2cbc09557ebd3 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 21:07:58 +0100 Subject: [PATCH 052/196] style: fix vertical spacing inconsistencies --- .../unibo/alchemist/boundary/dsl/DSLLoader.kt | 9 ---- .../boundary/dsl/model/ProgramsContextImpl.kt | 2 - .../alchemist/dsl/LayerComparisonUtils.kt | 5 -- .../dsl/PerformanceComparisonTest.kt | 15 ------ .../alchemist/dsl/RuntimeComparisonHelper.kt | 9 ---- .../alchemist/dsl/StaticComparisonHelper.kt | 49 ------------------- .../it/unibo/alchemist/dsl/TestComparators.kt | 3 -- 7 files changed, 92 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt index 660cc068ff..44c62ee850 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt @@ -45,10 +45,6 @@ abstract class DSLLoader>( } val typedCtx = ctx as SimulationContextImpl val envInstance = envFactory() as Environment - println("Environment instance: $envInstance") - println("applying dsl with values $values") - println("Build steps" + ctx.buildSteps) - val unknownVariableNames = values.keys - this@DSLLoader.variables.keys require(unknownVariableNames.isEmpty()) { "Unknown variables provided: $unknownVariableNames." + @@ -60,11 +56,9 @@ abstract class DSLLoader>( k to v() }.toMap(), ) - val simulationIstance = typedCtx.build(envInstance, values) val environment = simulationIstance.environment val engine = Engine(environment) - // MONITORS simulationIstance.monitors.forEach { monitor -> engine.addOutputMonitor(monitor) @@ -75,13 +69,10 @@ abstract class DSLLoader>( it.type?.bindDataExtractors(it.extractors) } } as List> - exporters.forEach { it.bindVariables(ctx.variablesContext.references.get()) } - if (exporters.isNotEmpty()) { engine.addOutputMonitor(GlobalExporter(exporters)) } - return engine } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt index d72e1881d1..917467ddd4 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt @@ -61,7 +61,6 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex logger.debug("Applying program to node at position: {}", position) val c = ProgramContextImpl(node).apply(program) val context = ctx.ctx.ctx - logger.debug("Creating time distribution for program") val timeDistribution = c.timeDistribution ?: context.incarnation.createTimeDistribution( @@ -84,7 +83,6 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex r.actions += c.actions.map { it() } logger.debug("Adding conditions to reaction") r.conditions += c.conditions.map { it() } - logger.debug("Adding reaction to node") if (filter == null || filter.contains(position)) { node.addReaction(r) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt index f98e6ad0eb..b27f46c60d 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt @@ -7,14 +7,10 @@ import org.junit.jupiter.api.Assertions.assertEquals object LayerComparisonUtils { fun > compareLayerValues(dslEnv: Environment, yamlEnv: Environment) { println("Comparing layer values...") - val samplePositions = mutableListOf

() - samplePositions.addAll(dslEnv.nodes.map { dslEnv.getPosition(it) }) samplePositions.addAll(yamlEnv.nodes.map { yamlEnv.getPosition(it) }) - val uniquePositions = samplePositions.distinct() - if (uniquePositions.isNotEmpty()) { for (position in uniquePositions) { val dslLayerValues = dslEnv.layers.map { it.getValue(position) } @@ -31,7 +27,6 @@ object LayerComparisonUtils { else -> value.toString().toDoubleOrNull() ?: 0.0 } } - assertEquals( dslDoubleValues, yamlDoubleValues, diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt index 206f4777d6..2823978b7b 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt @@ -67,48 +67,37 @@ class PerformanceComparisonTest { val originalOut = System.out val originalErr = System.err val nullStream = PrintStream(java.io.ByteArrayOutputStream()) - println("\n=== $testHeader ===") println("Resource: $yamlResource") println("Iterations: $iterations\n") - val yamlTimes = mutableListOf() val dslTimes = mutableListOf() - val dslUrl = ResourceLoader.getResource(dslResource)!! val ymlUrl = ResourceLoader.getResource(yamlResource)!! - repeat(iterations) { System.setOut(nullStream) System.setErr(nullStream) - val yamlTime = measureTime { val yamlLoader = LoadAlchemist.from(ymlUrl) assertNotNull(yamlLoader) yamlLoaderAction(yamlLoader) } - val dslTime = measureTime { val dslLoader = LoadAlchemist.from(dslUrl) assertNotNull(dslLoader) dslLoaderAction(dslLoader) } - System.setOut(originalOut) System.setErr(originalErr) - yamlTimes.add(yamlTime.inWholeMilliseconds) dslTimes.add(dslTime.inWholeMilliseconds) } - yamlTimes.forEachIndexed { index, time -> println("Iteration ${index + 1}: YAML=${time}ms, DSL=${dslTimes[index]}ms") } - val stats = calculateStats(yamlTimes, dslTimes) printResults(resultsHeader, stats) printSpeedup(stats, dslFasterMsg, yamlFasterMsg) - println("\n=== Test completed ===\n") } @@ -146,18 +135,14 @@ class PerformanceComparisonTest { fun `verify both loaders produce equivalent results`() { val yamlResource = "dsl/yml/19-performance.yml" val dslResource = "/dsl/kts/19-performance.alchemist.kts" - val dslUrl = requireNotNull(this.javaClass.getResource(dslResource)) { "Resource $dslResource not found on test classpath" } val dslFile = File(dslUrl.toURI()) - val yamlLoader = LoadAlchemist.from(ResourceLoader.getResource(yamlResource)!!) val dslLoader = LoadAlchemist.from(dslFile) - assertNotNull(yamlLoader) assertNotNull(dslLoader) - val dslLoaderFunction = { dslLoader } dslLoaderFunction.shouldEqual(yamlResource, includeRuntime = false) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt index ab0e0abad9..f99eacdd73 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt @@ -81,14 +81,10 @@ object RuntimeComparisonHelper { "Exactly one termination method must be provided: steps, targetTime, or stableForSteps. " + "Provided: $terminationMethods" } - val effectiveSteps = steps ?: 0L - println("Running simulations for comparison...") - val dslSimulation = dslLoader.getDefault() val yamlSimulation = yamlLoader.getDefault() - println( "DSL simulation initial step: ${dslSimulation.step}, " + "initial time: ${dslSimulation.time}", @@ -97,9 +93,7 @@ object RuntimeComparisonHelper { "YAML simulation initial step: ${yamlSimulation.step}, " + "initial time: ${yamlSimulation.time}", ) - addTerminators(dslSimulation, yamlSimulation, steps, targetTime, stableForSteps) - try { runAndCompareSimulations( dslSimulation, @@ -177,16 +171,13 @@ object RuntimeComparisonHelper { "DSL simulation completed with status: ${dslSimulation.status}, " + "step: ${dslSimulation.step}, time: ${dslSimulation.time}", ) - println("Running YAML simulation...") runSimulationSynchronously(yamlSimulation) println( "YAML simulation completed with status: ${yamlSimulation.status}, " + "step: ${yamlSimulation.step}, time: ${yamlSimulation.time}", ) - checkSimulationTimeAdvancement(dslSimulation, yamlSimulation, effectiveSteps, targetTime, stableForSteps) - val effectivePositionTolerance = positionTolerance ?: max(timeTolerance * 10, 1e-6) compareRuntimeStates( dslSimulation, diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt index 363277aa96..23c3c8a44d 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt @@ -37,7 +37,6 @@ object StaticComparisonHelper { dslLoader.constants, "Constants should match", ) - // Compare variables by name, default value, and full stream val yamlVariables = yamlLoader.variables val dslVariables = dslLoader.variables @@ -62,14 +61,12 @@ object StaticComparisonHelper { "Values stream of variable '$name' should match", ) } - // Compare remote dependencies assertEquals( yamlLoader.remoteDependencies, dslLoader.remoteDependencies, "Remote dependencies should match", ) - // Compare launcher types (not exact instances) assertEquals( yamlLoader.launcher::class, @@ -83,13 +80,10 @@ object StaticComparisonHelper { */ fun > compareSimulations(dslLoader: Loader, yamlLoader: Loader) { println("Comparing simulations...") - val yamlSimulation = yamlLoader.getDefault() val dslSimulation = dslLoader.getDefault() - // Compare environments compareEnvironments(dslSimulation.environment, yamlSimulation.environment) - // Compare simulation properties compareSimulationProperties(dslSimulation, yamlSimulation) } @@ -99,7 +93,6 @@ object StaticComparisonHelper { */ private fun > compareEnvironments(dslEnv: Environment, yamlEnv: Environment) { println("Comparing environments...") - // Compare node counts assertEquals( yamlEnv.nodes.size, @@ -114,7 +107,6 @@ object StaticComparisonHelper { dslNodeTypes, "Node types should match", ) - // Compare node positions val dslPositions = dslEnv.nodes.map { dslEnv.getPosition(it) }.toSet() val yamlPositions = yamlEnv.nodes.map { yamlEnv.getPosition(it) }.toSet() @@ -142,13 +134,10 @@ object StaticComparisonHelper { dslEnv.linkingRule::class, "Linking rule types should match", ) - // Compare neighborhoods induced by the linking rule compareNeighborhoods(dslEnv, yamlEnv) - // Compare programs (reactions) comparePrograms(dslEnv, yamlEnv) - // Compare layers compareLayers(dslEnv, yamlEnv) } @@ -159,30 +148,25 @@ object StaticComparisonHelper { private fun > compareNeighborhoods(dslEnv: Environment, yamlEnv: Environment) { val dslByPos = dslEnv.nodes.associateBy { dslEnv.getPosition(it) } val yamlByPos = yamlEnv.nodes.associateBy { yamlEnv.getPosition(it) } - // Positions should already match; guard to provide clearer error if not assertEquals( yamlByPos.keys, dslByPos.keys, "Node position sets should match before neighborhood comparison", ) - for (position in dslByPos.keys) { val dslNode = dslByPos.getValue(position) val yamlNode = yamlByPos.getValue(position) - val dslNeighborPositions = dslEnv .getNeighborhood(dslNode) .neighbors .map { dslEnv.getPosition(it) } .toSet() - val yamlNeighborPositions = yamlEnv .getNeighborhood(yamlNode) .neighbors .map { yamlEnv.getPosition(it) } .toSet() - assertEquals( yamlNeighborPositions, dslNeighborPositions, @@ -196,25 +180,20 @@ object StaticComparisonHelper { */ private fun > compareNodeContents(dslEnv: Environment, yamlEnv: Environment) { println("Comparing node contents...") - // Since we can't match by position, we'll compare all nodes by their contents val dslNodes = dslEnv.nodes.toList() val yamlNodes = yamlEnv.nodes.toList() - // Compare total molecule counts val dslTotalMolecules = dslNodes.sumOf { it.moleculeCount } val yamlTotalMolecules = yamlNodes.sumOf { it.moleculeCount } - assertEquals( yamlTotalMolecules, dslTotalMolecules, "Total molecule counts should match", ) - // Compare all node contents (without position matching) val dslContents = dslNodes.map { it.contents }.sortedBy { it.toString() } val yamlContents = yamlNodes.map { it.contents }.sortedBy { it.toString() } - assertEquals( yamlContents, dslContents, @@ -227,10 +206,8 @@ object StaticComparisonHelper { */ private fun > comparePrograms(dslEnv: Environment, yamlEnv: Environment) { println("Comparing programs...") - // Compare global reactions compareGlobalReactions(dslEnv, yamlEnv) - // Compare node reactions compareNodeReactions(dslEnv, yamlEnv) } @@ -240,20 +217,16 @@ object StaticComparisonHelper { */ private fun > compareGlobalReactions(dslEnv: Environment, yamlEnv: Environment) { println("Comparing global reactions...") - val dslGlobalReactions = dslEnv.globalReactions.toList() val yamlGlobalReactions = yamlEnv.globalReactions.toList() - assertEquals( yamlGlobalReactions.size, dslGlobalReactions.size, "Global reactions count should match", ) - // Compare global reaction types val dslGlobalTypes = dslGlobalReactions.map { it::class }.sortedBy { it.simpleName } val yamlGlobalTypes = yamlGlobalReactions.map { it::class }.sortedBy { it.simpleName } - assertEquals( yamlGlobalTypes, dslGlobalTypes, @@ -266,30 +239,24 @@ object StaticComparisonHelper { */ private fun > compareNodeReactions(dslEnv: Environment, yamlEnv: Environment) { println("Comparing node reactions...") - val dslNodes = dslEnv.nodes.toList() val yamlNodes = yamlEnv.nodes.toList() - // Compare total reaction counts val dslTotalReactions = dslNodes.sumOf { it.reactions.size } val yamlTotalReactions = yamlNodes.sumOf { it.reactions.size } - assertEquals( yamlTotalReactions, dslTotalReactions, "Total node reactions count should match", ) - // Compare reaction types across all nodes val dslReactionTypes = dslNodes.flatMap { it.reactions }.map { it::class }.sortedBy { it.simpleName } val yamlReactionTypes = yamlNodes.flatMap { it.reactions }.map { it::class }.sortedBy { it.simpleName } - assertEquals( yamlReactionTypes, dslReactionTypes, "Node reaction types should match", ) - // Compare reaction programs (conditions and actions) compareReactionPrograms(dslNodes, yamlNodes) } @@ -299,20 +266,16 @@ object StaticComparisonHelper { */ private fun compareReactionPrograms(dslNodes: List>, yamlNodes: List>) { println("Comparing reaction programs...") - // Compare total reactions count val dslTotalReactions = dslNodes.sumOf { it.reactions.size } val yamlTotalReactions = yamlNodes.sumOf { it.reactions.size } - assertEquals( yamlTotalReactions, dslTotalReactions, "Total reactions count should match", ) - val dslReactions = extractReactionInfo(dslNodes) val yamlReactions = extractReactionInfo(yamlNodes) - assertEquals( yamlReactions, dslReactions, @@ -351,7 +314,6 @@ object StaticComparisonHelper { */ private fun compareSimulationProperties(dslSimulation: Simulation<*, *>, yamlSimulation: Simulation<*, *>) { println("Comparing simulation properties...") - // Compare output monitors count assertEquals( yamlSimulation.outputMonitors.size, @@ -362,13 +324,11 @@ object StaticComparisonHelper { // Compare output monitor types by class since instances may differ val yamlMonitorTypes = yamlSimulation.outputMonitors.map { it::class } val dslMonitorTypes = dslSimulation.outputMonitors.map { it::class } - assertEquals( yamlMonitorTypes.sortedBy { it.simpleName }, dslMonitorTypes.sortedBy { it.simpleName }, "Output monitor types should match", ) - compareExporters(dslSimulation, yamlSimulation) } @@ -379,7 +339,6 @@ object StaticComparisonHelper { val yamlExporters = yamlSimulation.outputMonitors .filterIsInstance>() .flatMap { it.exporters } - assertEquals( yamlExporters.size, dslExporters.size, @@ -393,7 +352,6 @@ object StaticComparisonHelper { dslTypes, "Exporter types should match", ) - compareDataExtractors(dslExporters, yamlExporters) } @@ -405,7 +363,6 @@ object StaticComparisonHelper { dslTotal, "Total data extractor counts should match", ) - val dslTypes = dslExporters.flatMap { it.dataExtractors }.map { it::class }.sortedBy { it.simpleName } val yamlTypes = yamlExporters.flatMap { it.dataExtractors }.map { it::class }.sortedBy { it.simpleName } assertEquals( @@ -413,7 +370,6 @@ object StaticComparisonHelper { dslTypes, "Data extractor types should match", ) - val dslInfo = dslExporters.flatMap { it.dataExtractors }.map { extractor -> ExtractorInfo( type = extractor::class.simpleName.orEmpty(), @@ -445,27 +401,22 @@ object StaticComparisonHelper { */ private fun > compareLayers(dslEnv: Environment, yamlEnv: Environment) { println("Comparing layers...") - // Simplified check // If two layers have different molecules this test does not detect it. - // Compare layer counts assertEquals( yamlEnv.layers.size, dslEnv.layers.size, "Layer counts should match", ) - // Compare layer types val dslLayerTypes = dslEnv.layers.map { it::class }.sortedBy { it.simpleName } val yamlLayerTypes = yamlEnv.layers.map { it::class }.sortedBy { it.simpleName } - assertEquals( yamlLayerTypes, dslLayerTypes, "Layer types should match", ) - LayerComparisonUtils.compareLayerValues(dslEnv, yamlEnv) } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt index 6437057737..5fa9be9261 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt @@ -43,11 +43,9 @@ object TestComparators { timeTolerance: Double = 0.01, ) { val yamlLoader = LoaderFactory.loadYaml(yamlResource) - // Always perform static comparison StaticComparisonHelper.compareBasicProperties(dslLoader(), yamlLoader) StaticComparisonHelper.compareSimulations(dslLoader(), yamlLoader) - // Optionally perform runtime comparison if (includeRuntime) { RuntimeComparisonHelper.compareLoaders( @@ -116,7 +114,6 @@ object TestComparators { // Always perform static comparison StaticComparisonHelper.compareBasicProperties(dslLoader, yamlLoader) StaticComparisonHelper.compareSimulations(dslLoader, yamlLoader) - // Optionally perform runtime comparison if (includeRuntime) { RuntimeComparisonHelper.compareLoaders( From 52636bf8bec2df1f22402ddc2a3707afae16ce27 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 22:14:56 +0100 Subject: [PATCH 053/196] refactor: simplify expression --- .../boundary/dsl/processor/ConstructorFinder.kt | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt index d92ad9e502..4a747a565d 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt @@ -16,23 +16,16 @@ object ConstructorFinder { * @return The found constructor, or null if no suitable constructor exists */ // Prefer the primary constructor, but if it's missing or not public, pick the public constructor with the most params. - fun findConstructor(classDecl: KSClassDeclaration): KSFunctionDeclaration? { - val primaryConstructor = classDecl.primaryConstructor - if ( - primaryConstructor != null && - isPublicConstructor(primaryConstructor) - ) { - return primaryConstructor - } - val constructors = classDecl.getAllFunctions() + fun findConstructor(classDecl: KSClassDeclaration): KSFunctionDeclaration? = + classDecl.primaryConstructor?.takeIf { isPublicConstructor(it) } ?: classDecl + .getAllFunctions() .filter { function -> val simpleName = function.simpleName.asString() (simpleName == "" || simpleName == classDecl.simpleName.asString()) && isPublicConstructor(function) } .sortedByDescending { it.parameters.size } - return constructors.firstOrNull() - } + .firstOrNull() private fun isPublicConstructor(function: KSFunctionDeclaration): Boolean { val modifiers = function.modifiers From af61a31d5fad83ae481f8734c87a1c683646c3e6 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 22:43:34 +0100 Subject: [PATCH 054/196] refactor: simplify expressions --- .../dsl/processor/ConstructorParamBuilder.kt | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 33dc177e67..403cc1ae23 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -55,15 +55,7 @@ object ConstructorParamBuilder { ) } - private fun getDefaultParamName(injectionType: InjectionType): String = when (injectionType) { - InjectionType.ENVIRONMENT -> "env" - InjectionType.GENERATOR -> "generator" - InjectionType.INCARNATION -> "incarnation" - InjectionType.NODE -> "node" - InjectionType.REACTION -> "reaction" - InjectionType.TIMEDISTRIBUTION -> "timeDistribution" - InjectionType.FILTER -> "filter" - } + private fun getDefaultParamName(injectionType: InjectionType): String = injectionType.name.lowercase() private fun needsCast( constructorParamType: KSTypeReference, @@ -223,20 +215,23 @@ object ConstructorParamBuilder { injectionTypes: List>, ): InjectionType? { for ((type, annotationKey, checkAnnotation) in injectionTypes) { - val found = if (checkAnnotation) { - isInjectionIndex( - type, - index, - injectionContext.indices, - injectionContext.annotationValues, - annotationKey, - ) - } else { - injectionContext.indices.containsKey(type) && - index == injectionContext.indices[type] && - paramsToSkip.contains(index) - } - if (found) { + if (( + checkAnnotation && + isInjectionIndex( + type, + index, + injectionContext.indices, + injectionContext.annotationValues, + annotationKey, + ) + ) || + ( + !checkAnnotation && + injectionContext.indices.containsKey(type) && + index == injectionContext.indices[type] && + paramsToSkip.contains(index) + ) + ) { return type } } From a56fd436ff56e2365fc9cafc25236e82e0957333 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 26 Nov 2025 23:27:05 +0100 Subject: [PATCH 055/196] refactor: change annotation from @BuildDsl to @AlchemistKotlinDSL --- .../dsl/{BuildDsl.kt => AlchemistKotlinDSL.kt} | 2 +- .../dsl/processor/DslBuilderProcessor.kt | 17 +++++++++++------ .../boundary/dsl/processor/ParameterInjector.kt | 4 ++-- .../timedistributions/ExponentialTime.java | 4 ++-- .../alchemist/model/deployments/Circle.java | 4 ++-- .../deployments/GeometricGradientRectangle.java | 4 ++-- .../alchemist/model/deployments/Point.java | 4 ++-- .../alchemist/model/deployments/Rectangle.java | 4 ++-- .../alchemist/model/positionfilters/Circle.java | 4 ++-- .../model/positionfilters/Rectangle.java | 4 ++-- .../boundary/extractors/MoleculeReader.kt | 4 ++-- .../alchemist/model/deployments/CircularArc.kt | 4 ++-- .../model/deployments/CloseToAlreadyDeployed.kt | 4 ++-- .../model/deployments/GraphStreamDeployment.kt | 4 ++-- .../unibo/alchemist/model/deployments/Grid.kt | 4 ++-- .../alchemist/model/deployments/Polygon.kt | 4 ++-- .../model/deployments/SpecificPositions.kt | 4 ++-- .../unibo/alchemist/model/nodes/TestNode.java | 4 ++-- .../boundary/properties/TestNodeProperty.kt | 4 ++-- .../unibo/alchemist/test/GlobalTestReaction.kt | 4 ++-- 20 files changed, 48 insertions(+), 43 deletions(-) rename alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/{BuildDsl.kt => AlchemistKotlinDSL.kt} (98%) diff --git a/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt b/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt similarity index 98% rename from alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt rename to alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt index 1fa4e0daeb..62c63a9930 100644 --- a/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/BuildDsl.kt +++ b/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt @@ -35,7 +35,7 @@ package it.unibo.alchemist.boundary.dsl */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.SOURCE) -annotation class BuildDsl( +annotation class AlchemistKotlinDSL( val functionName: String = "", val scope: String = "", val injectEnvironment: Boolean = true, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 0b844c6371..057ac89120 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -9,15 +9,20 @@ import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSValueParameter import com.google.devtools.ksp.validate -import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import java.io.PrintWriter import java.nio.charset.StandardCharsets class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) : SymbolProcessor { override fun process(resolver: Resolver): List { - logger.info("DslBuilderProcessor: Starting processing") - logger.info("DslBuilderProcessor: BuildDsl qualified name: ${BuildDsl::class.qualifiedName}") - val annotationName = BuildDsl::class.qualifiedName ?: return emptyList() + logger.info( + "DslBuilderProcessor: Starting processing", + ) + logger.info( + "DslBuilderProcessor: AlchemistKotlinDSL qualified name: " + + "${AlchemistKotlinDSL::class.qualifiedName}", + ) + val annotationName = AlchemistKotlinDSL::class.qualifiedName ?: return emptyList() val symbols = resolver.getSymbolsWithAnnotation(annotationName) val symbolList = symbols.toList() logger.info("DslBuilderProcessor: Found ${symbolList.size} symbols with @BuildDsl annotation") @@ -52,10 +57,10 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger.info("DslBuilderProcessor: Processing class ${classDecl.simpleName.asString()}") logger.info("DslBuilderProcessor: Class qualified name: ${classDecl.qualifiedName?.asString()}") val annotation = classDecl.annotations.firstOrNull { - it.shortName.asString() == "BuildDsl" + it.shortName.asString() == "AlchemistKotlinDSL" } if (annotation == null) { - logger.warn("Class ${classDecl.simpleName.asString()} has no @BuildDsl annotation") + logger.warn("Class ${classDecl.simpleName.asString()} has no @AlchemistKotlinDSL annotation") return } val annotationValues = annotation.arguments diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index 75f7e8afcb..61be008bdb 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -181,7 +181,7 @@ object ParameterInjector { * If a manual scope is provided in the annotation, it takes precedence over automatic detection. * * @param injectionIndices Map of injection types to parameter indices - * @param annotationValues Annotation values from the BuildDsl annotation + * @param annotationValues Annotation values from the AlchemistKotlinDSL annotation * @return The determined context type */ // Determine which context is active by checking manual overrides first, then injection mix. @@ -242,7 +242,7 @@ object ParameterInjector { * Gets the set of parameter indices that should be skipped (injected from context). * * @param injectionIndices Map of injection types to parameter indices - * @param annotationValues Annotation values from the BuildDsl annotation + * @param annotationValues Annotation values from the AlchemistKotlinDSL annotation * @param contextType The context type to determine which parameters can be injected * @return Set of parameter indices to skip */ diff --git a/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java b/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java index 634a426bb4..adc9134d7c 100644 --- a/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java +++ b/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java @@ -10,7 +10,7 @@ package it.unibo.alchemist.model.timedistributions; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import it.unibo.alchemist.boundary.dsl.BuildDsl; +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Node; import it.unibo.alchemist.model.Time; @@ -26,7 +26,7 @@ * * @param concentration type */ -@BuildDsl +@AlchemistKotlinDSL public class ExponentialTime extends AbstractDistribution { @Serial diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java index 6e080f1629..195873e696 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java @@ -9,7 +9,7 @@ package it.unibo.alchemist.model.deployments; -import it.unibo.alchemist.boundary.dsl.BuildDsl; +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; import org.apache.commons.math3.random.RandomGenerator; @@ -24,7 +24,7 @@ /** * @param

{@link Position} type */ -@BuildDsl +@AlchemistKotlinDSL public final class Circle

> extends AbstractRandomDeployment

{ private final double centerX; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java index c1fa9f85e7..c403d76996 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java @@ -9,7 +9,7 @@ package it.unibo.alchemist.model.deployments; -import it.unibo.alchemist.boundary.dsl.BuildDsl; +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; import org.apache.commons.math3.distribution.ExponentialDistribution; @@ -23,7 +23,7 @@ * * @param

position type */ -@BuildDsl +@AlchemistKotlinDSL public final class GeometricGradientRectangle

> extends Rectangle

{ private final ExponentialDistribution exp; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java index 2c6b885bdc..ecaa271c16 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java @@ -9,7 +9,7 @@ package it.unibo.alchemist.model.deployments; -import it.unibo.alchemist.boundary.dsl.BuildDsl; +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Deployment; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; @@ -22,7 +22,7 @@ * * @param

position type */ -@BuildDsl(scope = "DEPLOYMENTS_CONTEXT") +@AlchemistKotlinDSL(scope = "DEPLOYMENTS_CONTEXT") public final class Point

> implements Deployment

{ private final double x; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java index 5ea0352c2e..f12ae1b5e4 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java @@ -9,7 +9,7 @@ package it.unibo.alchemist.model.deployments; -import it.unibo.alchemist.boundary.dsl.BuildDsl; +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; import org.apache.commons.math3.random.RandomGenerator; @@ -19,7 +19,7 @@ /** * @param

position type */ -@BuildDsl +@AlchemistKotlinDSL public class Rectangle

> extends AbstractRandomDeployment

{ private final double x; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java index 54c78818e6..9cb07c8745 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java @@ -9,7 +9,7 @@ package it.unibo.alchemist.model.positionfilters; -import it.unibo.alchemist.boundary.dsl.BuildDsl; +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Position2D; import java.awt.geom.Ellipse2D; @@ -19,7 +19,7 @@ * * @param

Position type */ -@BuildDsl(functionName = "CircleFilter") +@AlchemistKotlinDSL(functionName = "CircleFilter") public class Circle

> extends Abstract2DShape

{ /** diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java index be334feefb..41945306e8 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java @@ -9,7 +9,7 @@ package it.unibo.alchemist.model.positionfilters; -import it.unibo.alchemist.boundary.dsl.BuildDsl; +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Position2D; import java.awt.geom.Rectangle2D; @@ -22,7 +22,7 @@ * * @param

position type */ -@BuildDsl(functionName = "RectangleFilter") +@AlchemistKotlinDSL(functionName = "RectangleFilter") public class Rectangle

> extends Abstract2DShape

{ /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt index 7ef0cc1630..7022e6adfb 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt @@ -10,7 +10,7 @@ package it.unibo.alchemist.boundary.extractors import it.unibo.alchemist.boundary.ExportFilter -import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation @@ -35,7 +35,7 @@ import kotlin.math.min * aggregating data. If an empty list is passed, then the values * will be logged indipendently for each node. */ -@BuildDsl(scope = "EXPORTER_CONTEXT") +@AlchemistKotlinDSL(scope = "EXPORTER_CONTEXT") class MoleculeReader @JvmOverloads constructor( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt index 8e585bf1a0..77a7fcb998 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt @@ -1,6 +1,6 @@ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position2D @@ -21,7 +21,7 @@ import org.apache.commons.math3.random.RandomGenerator * * Default values generate a uniform deployment on a circumference. */ -@BuildDsl +@AlchemistKotlinDSL data class CircularArc

> @JvmOverloads constructor( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt index da3781226d..8cd745e3f5 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt @@ -9,7 +9,7 @@ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Position @@ -20,7 +20,7 @@ import org.apache.commons.math3.random.RandomGenerator * in the proximity of those already included in the environment. * Behaviour if there are no nodes already inserted is undefined. */ -@BuildDsl +@AlchemistKotlinDSL class CloseToAlreadyDeployed>( randomGenerator: RandomGenerator, environment: Environment, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt index 9b13705a51..d8fa638b96 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt @@ -9,7 +9,7 @@ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.LinkingRule @@ -20,7 +20,7 @@ import org.apache.commons.math3.random.RandomGenerator /** * A deployment based on a [GraphStream](https://github.com/graphstream) graph. */ -@BuildDsl +@AlchemistKotlinDSL class GraphStreamDeployment

( private val createLinks: Boolean, private val graphStreamSupport: GraphStreamSupport<*, P>, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt index 578d8e1703..11b5cb926a 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt @@ -8,7 +8,7 @@ */ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position @@ -46,7 +46,7 @@ import org.apache.commons.math3.random.RandomGenerator * @param yShift * how shifted should be positions along columns */ -@BuildDsl +@AlchemistKotlinDSL open class Grid @JvmOverloads constructor( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt index 1a7b59e34b..58e59c8435 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt @@ -9,7 +9,7 @@ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Position2D @@ -34,7 +34,7 @@ private typealias Point2D = Pair * undefined. There polygon is closed automatically (there is no need to pass the first point also as last element). * */ -@BuildDsl +@AlchemistKotlinDSL open class Polygon

>( environment: Environment<*, P>, randomGenerator: RandomGenerator, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt index 559ec7b9c5..c87a17f6ca 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt @@ -7,7 +7,7 @@ */ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position @@ -15,7 +15,7 @@ import it.unibo.alchemist.model.Position /** * Given an environment and a list of list of numbers, it creates a list of the right position type for the environment. */ -@BuildDsl +@AlchemistKotlinDSL class SpecificPositions(environment: Environment<*, *>, vararg positions: Iterable) : Deployment> { private val positions: List> = positions.map { environment.makePosition(*it.toList().toTypedArray()) } diff --git a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java index 9f5ecfe605..8c3d09989e 100644 --- a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java +++ b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java @@ -9,7 +9,7 @@ package it.unibo.alchemist.model.nodes; -import it.unibo.alchemist.boundary.dsl.BuildDsl; +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Environment; import java.io.Serial; @@ -17,7 +17,7 @@ /** * Generic node for testing purposes. */ -@BuildDsl(scope = "DEPLOYMENT_CONTEXT") +@AlchemistKotlinDSL(scope = "DEPLOYMENT_CONTEXT") public final class TestNode extends GenericNode { @Serial diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt index a1ea567ab7..1dd70d58c4 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt @@ -9,7 +9,7 @@ package it.unibo.alchemist.boundary.properties -import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Node @@ -18,7 +18,7 @@ import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.properties.AbstractNodeProperty import org.apache.commons.math3.random.RandomGenerator -@BuildDsl +@AlchemistKotlinDSL class TestNodeProperty>( node: Node, val environment: Environment, diff --git a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt index eba555d22c..de7f2d97e2 100644 --- a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt +++ b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt @@ -9,7 +9,7 @@ package it.unibo.alchemist.test -import it.unibo.alchemist.boundary.dsl.BuildDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Condition @@ -20,7 +20,7 @@ import it.unibo.alchemist.model.Time import it.unibo.alchemist.model.TimeDistribution import org.danilopianini.util.ListSet import org.danilopianini.util.ListSets -@BuildDsl(scope = "GLOBAL_PROGRAMS_CONTEXT") +@AlchemistKotlinDSL(scope = "GLOBAL_PROGRAMS_CONTEXT") class GlobalTestReaction(override val timeDistribution: TimeDistribution, val environment: Environment) : GlobalReaction { override fun compareTo(other: Actionable): Int = tau.compareTo(other.tau) From a6d8b1fd694244c0905adc279eaa6e8b069a8bb7 Mon Sep 17 00:00:00 2001 From: marco Date: Thu, 27 Nov 2025 00:22:33 +0100 Subject: [PATCH 056/196] docs: add missing documentation --- .../dsl/processor/ConstructorParamBuilder.kt | 25 ++++++++--- .../dsl/processor/DslBuilderProcessor.kt | 9 ++-- .../dsl/processor/FunctionGenerator.kt | 11 ++++- .../dsl/processor/GenerationContext.kt | 41 +++++++++++++++++++ 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 403cc1ae23..5b8b53ab27 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -3,6 +3,7 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter +/** Creates expressions for constructor arguments combining injections and call-site values. */ object ConstructorParamBuilder { /** * Walks constructor parameters in order and either injects context values @@ -94,6 +95,7 @@ object ConstructorParamBuilder { return constructorTypeStr != contextParamType } + /** Builds constructor params when a property context is applied. */ fun buildConstructorParamsForPropertyContext( constructorInfo: ConstructorInfo, injectionContext: InjectionContext, @@ -111,6 +113,7 @@ object ConstructorParamBuilder { ) } + /** Converts regular constructors into property-context-style accessors. */ fun convertToPropertyContextAccessors( constructorInfo: ConstructorInfo, injectionContext: InjectionContext, @@ -224,12 +227,13 @@ object ConstructorParamBuilder { injectionContext.annotationValues, annotationKey, ) - ) || - ( - !checkAnnotation && - injectionContext.indices.containsKey(type) && - index == injectionContext.indices[type] && - paramsToSkip.contains(index) + ) || ( + !checkAnnotation && matchesFallbackInjection( + index, + type, + injectionContext.indices, + paramsToSkip, + ) ) ) { return type @@ -237,4 +241,13 @@ object ConstructorParamBuilder { } return null } + + private fun matchesFallbackInjection( + index: Int, + type: InjectionType, + injectionIndices: Map, + paramsToSkip: Set, + ): Boolean = paramsToSkip.contains(index) && + injectionIndices.containsKey(type) && + index == injectionIndices[type] } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 057ac89120..e618388b9d 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -13,19 +13,22 @@ import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import java.io.PrintWriter import java.nio.charset.StandardCharsets +/** Symbol processor that emits DSL helpers for `@AlchemistKotlinDSL` classes. */ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) : SymbolProcessor { + /** + * Processes every `@AlchemistKotlinDSL` symbol, generating helpers and reporting unresolved ones. + */ override fun process(resolver: Resolver): List { logger.info( "DslBuilderProcessor: Starting processing", ) logger.info( - "DslBuilderProcessor: AlchemistKotlinDSL qualified name: " + - "${AlchemistKotlinDSL::class.qualifiedName}", + "DslBuilderProcessor: AlchemistKotlinDSL qualified name: ${AlchemistKotlinDSL::class.qualifiedName}", ) val annotationName = AlchemistKotlinDSL::class.qualifiedName ?: return emptyList() val symbols = resolver.getSymbolsWithAnnotation(annotationName) val symbolList = symbols.toList() - logger.info("DslBuilderProcessor: Found ${symbolList.size} symbols with @BuildDsl annotation") + logger.info("DslBuilderProcessor: Found ${symbolList.size} symbols with @AlchemistKotlinDSL annotation") symbolList.forEach { symbol -> val qualifiedName = when (symbol) { is KSClassDeclaration -> symbol.qualifiedName?.asString() ?: "unknown" diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt index 2470144140..8c1e28edb2 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt @@ -3,7 +3,9 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter +/** Emits the signature, call site, and accessor for generated DSL helpers. */ object FunctionGenerator { + /** Builds the helper function signature including context and receiver parts. */ fun buildFunctionSignature( functionName: String, className: String, @@ -31,7 +33,7 @@ object FunctionGenerator { return "${contextPart}fun$functionTypeParamString $receiverPart$functionName$functionParams: $returnType =" } - // Build the context receiver only when injections exist. + // Build the context receiver only when injections exist so the generated function can require ctx. private fun buildContextPart( injectedParams: List>, contextType: ContextType, @@ -65,6 +67,7 @@ object FunctionGenerator { return "context(ctx: $contextTypeName) " } + /** Reads the variance annotation (in/out) declared for a type parameter bound. */ fun extractVarianceFromBound(paramName: String, typeParamBounds: List): String { val paramIndex = typeParamBounds.indexOfFirst { it.startsWith("$paramName:") } if (paramIndex < 0) { @@ -86,6 +89,7 @@ object FunctionGenerator { } } + /** Returns the parameter list string for the remaining constructor arguments. */ fun buildFunctionParams( remainingParams: List, paramNames: List, @@ -112,6 +116,7 @@ object FunctionGenerator { @Suppress("UNUSED_PARAMETER") contextType: ContextType, ): String = EMPTY_RECEIVER + /** Delegates to [ConstructorParamBuilder] to build argument expressions. */ fun buildConstructorParams( constructorInfo: ConstructorInfo, injectionContext: InjectionContext, @@ -122,6 +127,7 @@ object FunctionGenerator { typeParamNames, ) + /** Formats the constructor invocation using the resolved parameters. */ fun buildConstructorCall( className: String, typeParamNames: List, @@ -144,15 +150,18 @@ object FunctionGenerator { return defaultValueExpr?.let { " = $it" }.orEmpty() } + /** Computes which type parameters the referenced type requires beyond the ones already known. */ fun collectNeededTypeParams(typeRef: KSTypeReference, existingTypeParamNames: List): Set = TypeParameterHandler.collectNeededTypeParams(typeRef, existingTypeParamNames) + /** Builds the context parameter type for the injected argument expression. */ fun buildContextParamType( typeRef: KSTypeReference, typeParamNames: MutableList, typeParamBounds: MutableList, ): String = TypeArgumentProcessor.buildContextParamType(typeRef, typeParamNames, typeParamBounds) + /** Builds property-context-specific constructor arguments. */ fun buildConstructorParamsForPropertyContext( constructorInfo: ConstructorInfo, injectionContext: InjectionContext, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt index 394ea1e761..458db1553d 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt @@ -3,6 +3,14 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSValueParameter +/** + * Captures the type parameter names and bounds needed inside the generated helper. + * + * @property names Generated type parameter identifiers. + * @property bounds Bounds for each generated type parameter. + * @property classTypeParamNames Original class-level type parameter names. + * @property classTypeParamBounds Original class-level type parameter bounds. + */ data class TypeParameterInfo( val names: List, val bounds: List, @@ -10,6 +18,15 @@ data class TypeParameterInfo( val classTypeParamBounds: List = bounds, ) +/** + * Describes the constructor parameters before and after injection filtering. + * + * @property allParameters All parameters declared on the constructor. + * @property remainingParams Parameters the caller still needs to provide. + * @property paramsToSkip Indexes of injected parameters inside the constructor. + * @property paramNames Names assigned to the remaining parameters. + * @property paramTypes Types of the remaining parameters. + */ data class ConstructorInfo( val allParameters: List, val remainingParams: List, @@ -18,6 +35,17 @@ data class ConstructorInfo( val paramTypes: List, ) +/** + * Represents the injected values and annotation-driven flags available during generation. + * + * @property indices Mapping of injection types to constructor indexes. + * @property paramNames Local names allocated to injected context parameters. + * @property paramTypes Types assigned to injected context parameters. + * @property annotationValues Extracted values from the `@BuildDsl` annotation. + * @property contextType Chosen context enum describing the current execution environment. + * @property hasContextParams Whether the helper defines context receivers. + * @property contextParamName Name of the context parameter used by accessors. + */ data class InjectionContext( val indices: Map, val paramNames: Map, @@ -28,6 +56,19 @@ data class InjectionContext( val contextParamName: String = "ctx", ) +/** + * Aggregates everything needed to emit a DSL helper for a specific class. + * + * @property classDecl The declaration being processed. + * @property className Simple name of the target class. + * @property functionName Generated helper function name. + * @property typeParams Type parameter metadata for the helper. + * @property constructorInfo Constructor metadata derived from the declaration. + * @property injectionContext Information about which parameters need injection. + * @property injectedParams List of injected parameter (name,type) pairs. + * @property defaultValues Default values inferred for remaining params. + * @property needsMapEnvironment Whether a `MapEnvironment` import is required. + */ data class GenerationContext( val classDecl: KSClassDeclaration, val className: String, From ee5613566a1cddb43687a5407a2c8723250b0ff4 Mon Sep 17 00:00:00 2001 From: marco Date: Thu, 27 Nov 2025 01:07:04 +0100 Subject: [PATCH 057/196] style: fix detekt errors --- .../dsl/processor/ConstructorFinder.kt | 4 +-- .../dsl/processor/ConstructorParamBuilder.kt | 33 +++++++++---------- .../processor/DslBuilderProcessorProvider.kt | 2 -- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt index 4a747a565d..fd9dd2d8f7 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt @@ -10,12 +10,12 @@ import com.google.devtools.ksp.symbol.Modifier object ConstructorFinder { /** * Finds a public constructor for the given class declaration. - * Prefers the primary constructor, otherwise returns the constructor with the most parameters. + * Prefers the primary constructor, otherwise returns the constructor + * with the most parameters. * * @param classDecl The class declaration to find a constructor for * @return The found constructor, or null if no suitable constructor exists */ - // Prefer the primary constructor, but if it's missing or not public, pick the public constructor with the most params. fun findConstructor(classDecl: KSClassDeclaration): KSFunctionDeclaration? = classDecl.primaryConstructor?.takeIf { isPublicConstructor(it) } ?: classDecl .getAllFunctions() diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 5b8b53ab27..15ee5e12bb 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -218,24 +218,21 @@ object ConstructorParamBuilder { injectionTypes: List>, ): InjectionType? { for ((type, annotationKey, checkAnnotation) in injectionTypes) { - if (( - checkAnnotation && - isInjectionIndex( - type, - index, - injectionContext.indices, - injectionContext.annotationValues, - annotationKey, - ) - ) || ( - !checkAnnotation && matchesFallbackInjection( - index, - type, - injectionContext.indices, - paramsToSkip, - ) - ) - ) { + val matchesAnnotation = checkAnnotation && + isInjectionIndex( + type, + index, + injectionContext.indices, + injectionContext.annotationValues, + annotationKey, + ) + val matchesFallback = !checkAnnotation && matchesFallbackInjection( + index, + type, + injectionContext.indices, + paramsToSkip, + ) + if (matchesAnnotation || matchesFallback) { return type } } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt index 686a312bc6..ed5d044265 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt @@ -1,7 +1,5 @@ package it.unibo.alchemist.boundary.dsl.processor -import com.google.devtools.ksp.processing.CodeGenerator -import com.google.devtools.ksp.processing.KSPLogger import com.google.devtools.ksp.processing.SymbolProcessor import com.google.devtools.ksp.processing.SymbolProcessorEnvironment import com.google.devtools.ksp.processing.SymbolProcessorProvider From 05a87529d417bf0b47b84ed6fac9300d4a16641c Mon Sep 17 00:00:00 2001 From: marco Date: Thu, 27 Nov 2025 02:17:34 +0100 Subject: [PATCH 058/196] style: fix detekt errors --- .../boundary/dsl/model/SimulationContextImpl.kt | 14 ++++---------- .../boundary/dsl/model/VariablesContext.kt | 4 ++-- .../boundary/dsl/scripting/AlchemistScript.kt | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt index 8965c566c5..bab2b2da0d 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -64,22 +64,16 @@ class SimulationContextImpl>(override val incarnation: Incarn private var _simulationGenerator: RandomGenerator? = null override var scenarioGenerator: RandomGenerator - get() = if (_scenarioGenerator == null) { - _scenarioGenerator = MersenneTwister(0L) - _scenarioGenerator!! - } else { - _scenarioGenerator!! + get() { + return _scenarioGenerator ?: MersenneTwister(0L).also { _scenarioGenerator = it } } set(value) { buildSteps.add { this._scenarioGenerator = value } } override var simulationGenerator: RandomGenerator - get() = if (_simulationGenerator == null) { - _simulationGenerator = MersenneTwister(0L) - _simulationGenerator!! - } else { - _simulationGenerator!! + get() { + return _simulationGenerator ?: MersenneTwister(0L).also { _simulationGenerator = it } } set(value) { buildSteps.add { this._simulationGenerator = value } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt index 3c131575f4..f60078b0cc 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt @@ -51,10 +51,10 @@ class VariablesContext { */ fun addReferences(newRefs: Map) { val currMap = references.get() - val newRefs = currMap.toMutableMap().also { m -> + val updatedMap = currMap.toMutableMap().also { m -> m.putAll(newRefs.mapValues { it.value as Any }) } - references.set(newRefs) + references.set(updatedMap) } /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt index 92868ea5fc..d3bd9c4bf8 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt @@ -27,7 +27,7 @@ import kotlin.script.experimental.jvm.jvm fileExtension = "alchemist.kts", compilationConfiguration = AlchemistCompilationConfiguration::class, ) -abstract class AlchemistScript +interface AlchemistScript /** * Compilation configuration for Alchemist scripts. From 51de749504965a1a85476350120654c04c3fdc66 Mon Sep 17 00:00:00 2001 From: marco Date: Fri, 28 Nov 2025 21:36:10 +0100 Subject: [PATCH 059/196] refactor: replace exporters function signature --- .../it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt | 2 +- .../unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 166942f76a..e87bd38d30 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -151,7 +151,7 @@ interface SimulationContext> { * @param block The configuration block * @see [ExporterContextImpl] */ - fun exporter(block: ExporterContextImpl.() -> Unit) + fun exporter(block: ExporterContext.() -> Unit) /** * Configures a global program. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt index bab2b2da0d..afce09c7d9 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -127,7 +127,7 @@ class SimulationContextImpl>(override val incarnation: Incarn buildSteps.add { OutputMonitorsContextImpl(this).block() } } - override fun exporter(block: ExporterContextImpl.() -> Unit) { + override fun exporter(block: ExporterContext.() -> Unit) { buildSteps.add { this.exporters.add(ExporterContextImpl(this).apply(block)) } } From 674e877556ebe97a0a3467daa64ff9cad11e59a7 Mon Sep 17 00:00:00 2001 From: marco Date: Fri, 28 Nov 2025 21:41:10 +0100 Subject: [PATCH 060/196] refactor: better performance test --- .../dsl/PerformanceComparisonTest.kt | 189 ++++++++++++------ .../dsl/kts/19-performance.alchemist.kts | 4 +- 2 files changed, 133 insertions(+), 60 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt index 2823978b7b..cc323081bf 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt @@ -14,43 +14,74 @@ import org.kaikikm.threadresloader.ResourceLoader class PerformanceComparisonTest { private data class PerformanceStats( - val avgYamlTime: Double, - val avgDslTime: Double, - val minYamlTime: Long, - val minDslTime: Long, - val maxYamlTime: Long, - val maxDslTime: Long, + val yamlLoadingTime: Long, + val dslLoadingTime: Long, + val avgYamlActionTime: Double, + val avgDslActionTime: Double, + val minYamlActionTime: Long, + val minDslActionTime: Long, + val maxYamlActionTime: Long, + val maxDslActionTime: Long, ) - private fun calculateStats(yamlTimes: List, dslTimes: List): PerformanceStats = PerformanceStats( - avgYamlTime = yamlTimes.average(), - avgDslTime = dslTimes.average(), - minYamlTime = yamlTimes.minOrNull() ?: 0L, - minDslTime = dslTimes.minOrNull() ?: 0L, - maxYamlTime = yamlTimes.maxOrNull() ?: 0L, - maxDslTime = dslTimes.maxOrNull() ?: 0L, + private fun calculateStats( + yamlLoadingTime: Long, + dslLoadingTime: Long, + yamlActionTimes: List, + dslActionTimes: List, + ): PerformanceStats = PerformanceStats( + yamlLoadingTime = yamlLoadingTime, + dslLoadingTime = dslLoadingTime, + avgYamlActionTime = yamlActionTimes.average(), + avgDslActionTime = dslActionTimes.average(), + minYamlActionTime = yamlActionTimes.minOrNull() ?: 0L, + minDslActionTime = dslActionTimes.minOrNull() ?: 0L, + maxYamlActionTime = yamlActionTimes.maxOrNull() ?: 0L, + maxDslActionTime = dslActionTimes.maxOrNull() ?: 0L, ) private fun printResults(header: String, stats: PerformanceStats) { println("\n=== $header ===") println("YAML Loader:") - println(" Average: ${String.format(Locale.US, "%.2f", stats.avgYamlTime)} ms") - println(" Min: ${stats.minYamlTime} ms") - println(" Max: ${stats.maxYamlTime} ms") + println(" Loading Phase:") + println(" Time: ${stats.yamlLoadingTime} ms") + println(" Action Phase:") + println(" Average: ${String.format(Locale.US, "%.2f", stats.avgYamlActionTime)} ms") + println(" Min: ${stats.minYamlActionTime} ms") + println(" Max: ${stats.maxYamlActionTime} ms") + println( + " Total Average: ${String.format( + Locale.US, + "%.2f", + stats.yamlLoadingTime + stats.avgYamlActionTime, + )} ms", + ) println("\nDSL Loader:") - println(" Average: ${String.format(Locale.US, "%.2f", stats.avgDslTime)} ms") - println(" Min: ${stats.minDslTime} ms") - println(" Max: ${stats.maxDslTime} ms") + println(" Loading Phase:") + println(" Time: ${stats.dslLoadingTime} ms") + println(" Action Phase:") + println(" Average: ${String.format(Locale.US, "%.2f", stats.avgDslActionTime)} ms") + println(" Min: ${stats.minDslActionTime} ms") + println(" Max: ${stats.maxDslActionTime} ms") + println( + " Total Average: ${String.format(Locale.US, "%.2f", stats.dslLoadingTime + stats.avgDslActionTime)} ms", + ) } private fun printSpeedup(stats: PerformanceStats, dslFasterMsg: String, yamlFasterMsg: String) { - val speedup = stats.avgYamlTime / stats.avgDslTime - println("\nSpeedup: ${String.format(Locale.US, "%.2f", speedup)}x") + val totalYamlTime = stats.yamlLoadingTime + stats.avgYamlActionTime + val totalDslTime = stats.dslLoadingTime + stats.avgDslActionTime + val speedup = totalYamlTime / totalDslTime + println("\nSpeedup (Total): ${String.format(Locale.US, "%.2f", speedup)}x") if (speedup > 1.0) { println("$dslFasterMsg ${String.format(Locale.US, "%.2f", speedup)}x faster than YAML") } else { println("$yamlFasterMsg ${String.format(Locale.US, "%.2f", 1.0 / speedup)}x faster than DSL") } + val loadingSpeedup = stats.yamlLoadingTime.toDouble() / stats.dslLoadingTime.toDouble() + println("Loading Phase Speedup: ${String.format(Locale.US, "%.2f", loadingSpeedup)}x") + val actionSpeedup = stats.avgYamlActionTime / stats.avgDslActionTime + println("Action Phase Speedup: ${String.format(Locale.US, "%.2f", actionSpeedup)}x") } private fun runPerformanceTest( @@ -63,71 +94,113 @@ class PerformanceComparisonTest { yamlFasterMsg: String, yamlLoaderAction: (Loader) -> Unit, dslLoaderAction: (Loader) -> Unit, - ) { + ): PerformanceStats { val originalOut = System.out val originalErr = System.err val nullStream = PrintStream(java.io.ByteArrayOutputStream()) println("\n=== $testHeader ===") println("Resource: $yamlResource") println("Iterations: $iterations\n") - val yamlTimes = mutableListOf() - val dslTimes = mutableListOf() + val yamlActionTimes = mutableListOf() + val dslActionTimes = mutableListOf() val dslUrl = ResourceLoader.getResource(dslResource)!! val ymlUrl = ResourceLoader.getResource(yamlResource)!! + System.setOut(nullStream) + System.setErr(nullStream) + var yamlLoader: Loader? = null + val yamlLoadingTime = measureTime { + yamlLoader = LoadAlchemist.from(ymlUrl) + } + assertNotNull(yamlLoader) + var dslLoader: Loader? = null + val dslLoadingTime = measureTime { + dslLoader = LoadAlchemist.from(dslUrl) + } + assertNotNull(dslLoader) + System.setOut(originalOut) + System.setErr(originalErr) repeat(iterations) { System.setOut(nullStream) System.setErr(nullStream) - val yamlTime = measureTime { - val yamlLoader = LoadAlchemist.from(ymlUrl) - assertNotNull(yamlLoader) - yamlLoaderAction(yamlLoader) + val yamlActionTime = measureTime { + yamlLoaderAction(yamlLoader!!) } - val dslTime = measureTime { - val dslLoader = LoadAlchemist.from(dslUrl) - assertNotNull(dslLoader) - dslLoaderAction(dslLoader) + val dslActionTime = measureTime { + dslLoaderAction(dslLoader!!) } System.setOut(originalOut) System.setErr(originalErr) - yamlTimes.add(yamlTime.inWholeMilliseconds) - dslTimes.add(dslTime.inWholeMilliseconds) - } - yamlTimes.forEachIndexed { index, time -> - println("Iteration ${index + 1}: YAML=${time}ms, DSL=${dslTimes[index]}ms") + yamlActionTimes.add(yamlActionTime.inWholeMilliseconds) + dslActionTimes.add(dslActionTime.inWholeMilliseconds) } - val stats = calculateStats(yamlTimes, dslTimes) + val stats = calculateStats( + yamlLoadingTime.inWholeMilliseconds, + dslLoadingTime.inWholeMilliseconds, + yamlActionTimes, + dslActionTimes, + ) printResults(resultsHeader, stats) printSpeedup(stats, dslFasterMsg, yamlFasterMsg) println("\n=== Test completed ===\n") + return stats + } + private fun runTestWith( + name: String, + action: (Loader) -> Unit, + testName: String, + iterations: Int = 10, + ): PerformanceStats { + val dslResource = "dsl/kts/$name.alchemist.kts" + val yamlResource = "dsl/yml/$name.yml" + return runPerformanceTest( + testHeader = testName, + yamlResource = yamlResource, + dslResource = dslResource, + iterations = iterations, + resultsHeader = "Results", + dslFasterMsg = "DSL loading is", + yamlFasterMsg = "YAML loading is", + yamlLoaderAction = action, + dslLoaderAction = action, + ) } @Test fun > `performance comparison between YAML and DSL loaders`() { - runPerformanceTest( - testHeader = "Performance Test: YAML vs DSL Loader", - yamlResource = "dsl/yml/19-performance.yml", - dslResource = "dsl/kts/19-performance.alchemist.kts", - iterations = 5, - resultsHeader = "Results", - dslFasterMsg = "DSL is", - yamlFasterMsg = "YAML is", - yamlLoaderAction = { it.getDefault() }, - dslLoaderAction = { it.getDefault() }, + runTestWith( + "19-performance", + testName = "Performance Test: YAML vs DSL Loader", + action = { it.getDefault() }, + iterations = 20, ) } @Test fun `performance comparison - loading phase only`() { - runPerformanceTest( - testHeader = "Performance Test: Loading Phase Only (YAML vs DSL)", - yamlResource = "dsl/yml/19-performance.yml", - dslResource = "dsl/kts/19-performance.alchemist.kts", - iterations = 10, - resultsHeader = "Results (Loading Phase Only)", - dslFasterMsg = "DSL loading is", - yamlFasterMsg = "YAML loading is", - yamlLoaderAction = {}, - dslLoaderAction = {}, + val stats = mutableListOf() + repeat(50) { + stats += runTestWith( + "19-performance", + action = {}, + testName = "Performance Test: Loading Phase Only ", + ) + } + val avgYamlLoadingTime = stats.map { it.yamlLoadingTime }.average() + val avgDslLoadingTime = stats.map { it.dslLoadingTime }.average() + println("\n=== Loading Phase Only Average Results ===") + println( + "YAML Loader Average Loading Time: ${String.format( + Locale.US, + "%.2f", + avgYamlLoadingTime, + )} ms", + ) + println( + "DSL Loader Average Loading Time: ${String.format( + Locale.US, + "%.2f", + avgDslLoadingTime, + )} ms", ) } diff --git a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts index 4a2f873b40..420f9be133 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts @@ -6,8 +6,8 @@ import it.unibo.alchemist.boundary.extractors.Time import org.apache.commons.math3.random.MersenneTwister val incarnation = SAPERE.incarnation() -val environment = Continuous2DEnvironment(incarnation) -simulation(incarnation, { environment }) { +val environment = {Continuous2DEnvironment(incarnation)} +simulation(incarnation, environment) { simulationGenerator = MersenneTwister(24L) scenarioGenerator = MersenneTwister(42L) From 2ea8fc0bf2c84e10f26de1aa3c7ad0dff3a9d45d Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 12:07:11 +0000 Subject: [PATCH 061/196] chore(build): update the javadoc.io cache --- .../alchemist-web-renderer/42.3.34.list | 282 ------------------ 1 file changed, 282 deletions(-) diff --git a/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.34.list b/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.34.list index 415747ae38..e69de29bb2 100644 --- a/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.34.list +++ b/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.34.list @@ -1,282 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:it.unibo.alchemist.boundary.launchers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/index.html -$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/index.html -$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/WebRendererLauncher/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/-web-renderer-launcher.html -$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/launch/#it.unibo.alchemist.boundary.Loader/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/launch.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//Button/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButtonGroup/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/active/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/active.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/disabled/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/disabled.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/onClick/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/on-click.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/variant.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/defaultValue/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/default-value.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/name.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/onChange/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/on-change.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/size/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/size.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/type/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/type.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/id.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/value/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/value.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//Modal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalBody/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-body.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalFooter/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-footer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalHeader/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalTitle/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps/closeButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/close-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/onHide/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/on-hide.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/show/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/show.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps/className/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/class-name.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//Navbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//NavbarBrand/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-brand.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/bg/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/bg.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/variant.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/client/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/client.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/endpoint/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/endpoint.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentClient/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-client.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentServer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-server.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/getSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/get-simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/pauseSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/pause-simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/playSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/play-simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppContent/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-content.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppNavbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-navbar.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//PlayButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//RenderModeButtons/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-render-mode-buttons.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//WarningModal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps/status/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/message/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/message.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/title/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/title.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic//updateState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.client.logic.UpdateStateStrategy#it.unibo.alchemist.boundary.webui.client.logic.AutoRenderModeStrategy/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/update-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/invoke.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/HwAutoRenderModeStrategy/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/-hw-auto-render-mode-strategy.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/invoke.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/minHwConcurrency/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/min-hw-concurrency.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/RESTUpdateStateStrategy/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/-r-e-s-t-update-state-strategy.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/client-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/retrieve-simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/server-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/client-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/retrieve-simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/server-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/SetBitmap/#korlibs.image.bitmap.Bitmap?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/-set-bitmap.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/bitmap.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/SetPlayButton/#it.unibo.alchemist.boundary.webui.common.utility.Action/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/-set-play-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/action/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/action.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/SetRenderMode/#it.unibo.alchemist.boundary.webui.common.model.RenderMode/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/-set-render-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/render-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/SetStatusSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/-set-status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//bitmapReducer/#korlibs.image.bitmap.Bitmap?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/bitmap-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//playButtonReducer/#it.unibo.alchemist.boundary.webui.common.utility.Action#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/play-button-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//renderModeReducer/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/render-mode-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//statusSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/status-surrogate-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state//rootReducer/#it.unibo.alchemist.boundary.webui.client.state.ClientState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/root-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/ClientState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.common.utility.Action#korlibs.image.bitmap.Bitmap?#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/-client-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/bitmap.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/playButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/play-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/render-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/store.html -$dokka.location:it.unibo.alchemist.boundary.webui.client////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client//App/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/-app.html -$dokka.location:it.unibo.alchemist.boundary.webui.client//main/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/main.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//decodeEnvironmentSurrogate/kotlinx.serialization.json.Json#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/decode-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//encodeEnvironmentSurrogate/kotlinx.serialization.json.Json#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/encode-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//jsonFormat/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/json-format.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules/concentrationModule/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/concentration-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EmptyConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-empty-concentration-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/polymorphicSerializer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/polymorphic-serializer.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/uninitializedEnvironment/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/uninitialized-environment.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/EnvironmentSurrogate/#kotlin.Int#kotlin.collections.List[it.unibo.alchemist.boundary.webui.common.model.surrogate.NodeSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/nodes/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/nodes.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/GeneralPositionSurrogate/#kotlin.DoubleArray#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/-general-position-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/coordinates.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/equals/#kotlin.Any?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/equals.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/hashCode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/hash-code.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/MoleculeSurrogate/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/-molecule-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/name.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/descriptor.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/deserialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/serialize/#kotlinx.serialization.encoding.Encoder#it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/serialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/NodeSurrogate/#kotlin.Int#kotlin.collections.Map[it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate,TypeParam(bounds=[kotlin.Any])]#TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/-node-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/contents/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/contents.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/id.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/position/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/position.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/Position2DSurrogate/#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/-position2-d-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/coordinates.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/x/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/x.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/y/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/y.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/coordinates.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.INIT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-i-n-i-t/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.PAUSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-p-a-u-s-e-d/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.READY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-e-a-d-y/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.RUNNING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-u-n-n-i-n-g/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.TERMINATED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-t-e-r-m-i-n-a-t-e-d/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/entries.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/value-of.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/values.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.AUTO///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-a-u-t-o/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.CLIENT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-c-l-i-e-n-t/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.SERVER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-s-e-r-v-e-r/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/entries.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/value-of.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/values.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/descriptor.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/deserialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/serialize/#kotlinx.serialization.encoding.Encoder#korlibs.image.bitmap.Bitmap32/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/serialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/BitmapRenderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/-bitmap-renderer.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/render.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/render.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/CommonState/#it.unibo.alchemist.boundary.webui.common.renderer.Renderer[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate,korlibs.image.bitmap.Bitmap]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/-common-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/renderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/renderer.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PAUSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-a-u-s-e/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PLAY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-l-a-y/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/entries.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/value-of.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/values.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_CLIENT_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-c-l-i-e-n-t_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_SERVER_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-s-e-r-v-e-r_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PAUSE_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-a-u-s-e_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PLAY_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-l-a-y_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_STATUS_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-s-t-a-t-u-s_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//installModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/install-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//routingModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/routing-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//startBrowserModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/start-browser-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/EnvironmentMonitor/#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/-environment-monitor.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/finished/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/finished.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/initialized/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/initialized.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/stepDone/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Actionable[TypeParam(bounds=[kotlin.Any?])]?#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/step-done.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory/makeEnvironmentMonitor/#it.unibo.alchemist.model.Environment[*,*]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/make-environment-monitor.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes//mainRoute/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/main-route.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentClientMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-client-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentServerMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-server-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPause/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-pause.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPlay/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-play.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationStatus/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/SetEnvironmentSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/-set-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/SetSimulation/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/-set-simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//environmentSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/environment-surrogate-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//simulationReducer/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/simulation-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state//rootReducer/#it.unibo.alchemist.boundary.webui.server.state.ServerState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/root-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/ServerState/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/-server-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/store.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toMoleculeSurrogate/it.unibo.alchemist.model.Molecule#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-molecule-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toNodeSurrogate/it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-node-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toStatusSurrogate/it.unibo.alchemist.core.Status#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate/toEmptyConcentration/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/to-empty-concentration.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate/toSuitablePositionSurrogate/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/to-suitable-position-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion/respond/io.ktor.server.routing.RoutingContext#it.unibo.alchemist.boundary.webui.server.utility.Response[TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/respond.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/Response/#io.ktor.http.HttpStatusCode#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-response.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/code/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/code.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/content/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/content.html -it.unibo.alchemist.boundary.launchers -it.unibo.alchemist.boundary.webui.client -it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons -it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal -it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar -it.unibo.alchemist.boundary.webui.client.api -it.unibo.alchemist.boundary.webui.client.api.utility -it.unibo.alchemist.boundary.webui.client.components -it.unibo.alchemist.boundary.webui.client.logic -it.unibo.alchemist.boundary.webui.client.state -it.unibo.alchemist.boundary.webui.client.state.actions -it.unibo.alchemist.boundary.webui.client.state.reducers -it.unibo.alchemist.boundary.webui.common.model -it.unibo.alchemist.boundary.webui.common.model.serialization -it.unibo.alchemist.boundary.webui.common.model.surrogate -it.unibo.alchemist.boundary.webui.common.renderer -it.unibo.alchemist.boundary.webui.common.state -it.unibo.alchemist.boundary.webui.common.utility -it.unibo.alchemist.boundary.webui.server.modules -it.unibo.alchemist.boundary.webui.server.monitor -it.unibo.alchemist.boundary.webui.server.routes -it.unibo.alchemist.boundary.webui.server.state -it.unibo.alchemist.boundary.webui.server.state.actions -it.unibo.alchemist.boundary.webui.server.state.reducers -it.unibo.alchemist.boundary.webui.server.surrogates.utility -it.unibo.alchemist.boundary.webui.server.utility From 95077460679a849fba0d6f12990df097ba8343c2 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 12:33:28 +0000 Subject: [PATCH 062/196] chore(build): update the javadoc.io cache --- .../svgSalamander/1.1.3.list | 13 - .../alchemist-web-renderer/42.3.18.list | 282 ++++++++++++++++++ .../org.danilopianini/conrec/0.1.1.list | 1 - 3 files changed, 282 insertions(+), 14 deletions(-) delete mode 100644 dokka-cache/guru.nidi.com.kitfox/svgSalamander/1.1.3.list create mode 100644 dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list delete mode 100644 dokka-cache/org.danilopianini/conrec/0.1.1.list diff --git a/dokka-cache/guru.nidi.com.kitfox/svgSalamander/1.1.3.list b/dokka-cache/guru.nidi.com.kitfox/svgSalamander/1.1.3.list deleted file mode 100644 index 35698a1d34..0000000000 --- a/dokka-cache/guru.nidi.com.kitfox/svgSalamander/1.1.3.list +++ /dev/null @@ -1,13 +0,0 @@ -com.kitfox.svg -com.kitfox.svg.animation -com.kitfox.svg.animation.parser -com.kitfox.svg.app -com.kitfox.svg.app.ant -com.kitfox.svg.app.beans -com.kitfox.svg.app.data -com.kitfox.svg.composite -com.kitfox.svg.pathcmd -com.kitfox.svg.pattern -com.kitfox.svg.util -com.kitfox.svg.xml -com.kitfox.svg.xml.cpx diff --git a/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list b/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list new file mode 100644 index 0000000000..415747ae38 --- /dev/null +++ b/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list @@ -0,0 +1,282 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:it.unibo.alchemist.boundary.launchers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/index.html +$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/index.html +$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/WebRendererLauncher/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/-web-renderer-launcher.html +$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/launch/#it.unibo.alchemist.boundary.Loader/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/launch.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//Button/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButtonGroup/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/active/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/active.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/disabled/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/disabled.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/onClick/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/on-click.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/variant.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/defaultValue/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/default-value.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/name.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/onChange/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/on-change.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/size/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/size.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/type/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/type.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/id.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/value/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/value.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//Modal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalBody/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-body.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalFooter/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-footer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalHeader/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalTitle/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps/closeButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/close-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/onHide/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/on-hide.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/show/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/show.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps/className/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/class-name.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//Navbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//NavbarBrand/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-brand.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/bg/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/bg.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/variant.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/client/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/client.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/endpoint/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/endpoint.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentClient/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-client.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentServer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-server.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/getSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/get-simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/pauseSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/pause-simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/playSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/play-simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppContent/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-content.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppNavbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-navbar.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//PlayButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//RenderModeButtons/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-render-mode-buttons.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//WarningModal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps/status/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/message/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/message.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/title/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/title.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic//updateState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.client.logic.UpdateStateStrategy#it.unibo.alchemist.boundary.webui.client.logic.AutoRenderModeStrategy/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/update-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/invoke.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/HwAutoRenderModeStrategy/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/-hw-auto-render-mode-strategy.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/invoke.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/minHwConcurrency/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/min-hw-concurrency.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/RESTUpdateStateStrategy/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/-r-e-s-t-update-state-strategy.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/client-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/retrieve-simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/server-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/client-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/retrieve-simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/server-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/SetBitmap/#korlibs.image.bitmap.Bitmap?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/-set-bitmap.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/bitmap.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/SetPlayButton/#it.unibo.alchemist.boundary.webui.common.utility.Action/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/-set-play-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/action/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/action.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/SetRenderMode/#it.unibo.alchemist.boundary.webui.common.model.RenderMode/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/-set-render-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/render-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/SetStatusSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/-set-status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//bitmapReducer/#korlibs.image.bitmap.Bitmap?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/bitmap-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//playButtonReducer/#it.unibo.alchemist.boundary.webui.common.utility.Action#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/play-button-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//renderModeReducer/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/render-mode-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//statusSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/status-surrogate-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state//rootReducer/#it.unibo.alchemist.boundary.webui.client.state.ClientState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/root-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/ClientState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.common.utility.Action#korlibs.image.bitmap.Bitmap?#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/-client-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/bitmap.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/playButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/play-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/render-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/store.html +$dokka.location:it.unibo.alchemist.boundary.webui.client////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client//App/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/-app.html +$dokka.location:it.unibo.alchemist.boundary.webui.client//main/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/main.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//decodeEnvironmentSurrogate/kotlinx.serialization.json.Json#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/decode-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//encodeEnvironmentSurrogate/kotlinx.serialization.json.Json#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/encode-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//jsonFormat/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/json-format.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules/concentrationModule/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/concentration-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EmptyConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-empty-concentration-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/polymorphicSerializer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/polymorphic-serializer.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/uninitializedEnvironment/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/uninitialized-environment.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/EnvironmentSurrogate/#kotlin.Int#kotlin.collections.List[it.unibo.alchemist.boundary.webui.common.model.surrogate.NodeSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/nodes/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/nodes.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/GeneralPositionSurrogate/#kotlin.DoubleArray#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/-general-position-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/equals/#kotlin.Any?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/equals.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/hashCode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/hash-code.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/MoleculeSurrogate/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/-molecule-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/name.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/descriptor.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/deserialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/serialize/#kotlinx.serialization.encoding.Encoder#it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/serialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/NodeSurrogate/#kotlin.Int#kotlin.collections.Map[it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate,TypeParam(bounds=[kotlin.Any])]#TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/-node-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/contents/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/contents.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/id.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/position/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/position.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/Position2DSurrogate/#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/-position2-d-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/x/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/x.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/y/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/y.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.INIT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-i-n-i-t/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.PAUSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-p-a-u-s-e-d/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.READY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-e-a-d-y/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.RUNNING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-u-n-n-i-n-g/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.TERMINATED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-t-e-r-m-i-n-a-t-e-d/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/entries.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/value-of.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/values.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.AUTO///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-a-u-t-o/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.CLIENT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-c-l-i-e-n-t/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.SERVER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-s-e-r-v-e-r/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/entries.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/value-of.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/values.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/descriptor.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/deserialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/serialize/#kotlinx.serialization.encoding.Encoder#korlibs.image.bitmap.Bitmap32/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/serialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/BitmapRenderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/-bitmap-renderer.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/render.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/render.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/CommonState/#it.unibo.alchemist.boundary.webui.common.renderer.Renderer[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate,korlibs.image.bitmap.Bitmap]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/-common-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/renderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/renderer.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PAUSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-a-u-s-e/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PLAY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-l-a-y/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/entries.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/value-of.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/values.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_CLIENT_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-c-l-i-e-n-t_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_SERVER_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-s-e-r-v-e-r_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PAUSE_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-a-u-s-e_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PLAY_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-l-a-y_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_STATUS_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-s-t-a-t-u-s_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//installModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/install-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//routingModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/routing-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//startBrowserModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/start-browser-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/EnvironmentMonitor/#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/-environment-monitor.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/finished/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/finished.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/initialized/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/initialized.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/stepDone/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Actionable[TypeParam(bounds=[kotlin.Any?])]?#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/step-done.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory/makeEnvironmentMonitor/#it.unibo.alchemist.model.Environment[*,*]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/make-environment-monitor.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes//mainRoute/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/main-route.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentClientMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-client-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentServerMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-server-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPause/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-pause.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPlay/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-play.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationStatus/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/SetEnvironmentSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/-set-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/SetSimulation/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/-set-simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//environmentSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/environment-surrogate-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//simulationReducer/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/simulation-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state//rootReducer/#it.unibo.alchemist.boundary.webui.server.state.ServerState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/root-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/ServerState/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/-server-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/store.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toMoleculeSurrogate/it.unibo.alchemist.model.Molecule#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-molecule-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toNodeSurrogate/it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-node-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toStatusSurrogate/it.unibo.alchemist.core.Status#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate/toEmptyConcentration/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/to-empty-concentration.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate/toSuitablePositionSurrogate/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/to-suitable-position-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion/respond/io.ktor.server.routing.RoutingContext#it.unibo.alchemist.boundary.webui.server.utility.Response[TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/respond.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/Response/#io.ktor.http.HttpStatusCode#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-response.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/code/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/code.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/content/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/content.html +it.unibo.alchemist.boundary.launchers +it.unibo.alchemist.boundary.webui.client +it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons +it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal +it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar +it.unibo.alchemist.boundary.webui.client.api +it.unibo.alchemist.boundary.webui.client.api.utility +it.unibo.alchemist.boundary.webui.client.components +it.unibo.alchemist.boundary.webui.client.logic +it.unibo.alchemist.boundary.webui.client.state +it.unibo.alchemist.boundary.webui.client.state.actions +it.unibo.alchemist.boundary.webui.client.state.reducers +it.unibo.alchemist.boundary.webui.common.model +it.unibo.alchemist.boundary.webui.common.model.serialization +it.unibo.alchemist.boundary.webui.common.model.surrogate +it.unibo.alchemist.boundary.webui.common.renderer +it.unibo.alchemist.boundary.webui.common.state +it.unibo.alchemist.boundary.webui.common.utility +it.unibo.alchemist.boundary.webui.server.modules +it.unibo.alchemist.boundary.webui.server.monitor +it.unibo.alchemist.boundary.webui.server.routes +it.unibo.alchemist.boundary.webui.server.state +it.unibo.alchemist.boundary.webui.server.state.actions +it.unibo.alchemist.boundary.webui.server.state.reducers +it.unibo.alchemist.boundary.webui.server.surrogates.utility +it.unibo.alchemist.boundary.webui.server.utility diff --git a/dokka-cache/org.danilopianini/conrec/0.1.1.list b/dokka-cache/org.danilopianini/conrec/0.1.1.list deleted file mode 100644 index 55d3475f3d..0000000000 --- a/dokka-cache/org.danilopianini/conrec/0.1.1.list +++ /dev/null @@ -1 +0,0 @@ -conrec From 3c66daa9b372b7834abf82538ddb02ef10000a72 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 12:47:35 +0000 Subject: [PATCH 063/196] chore(build): update the javadoc.io cache --- .../caffeine/3.2.3.list | 3 --- .../guru.nidi.com.kitfox/svgSalamander/1.1.3.list | 13 +++++++++++++ dokka-cache/org.danilopianini/conrec/0.1.1.list | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) delete mode 100644 dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list create mode 100644 dokka-cache/guru.nidi.com.kitfox/svgSalamander/1.1.3.list create mode 100644 dokka-cache/org.danilopianini/conrec/0.1.1.list diff --git a/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list b/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list deleted file mode 100644 index ae20519915..0000000000 --- a/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list +++ /dev/null @@ -1,3 +0,0 @@ -module:com.github.benmanes.caffeine -com.github.benmanes.caffeine.cache -com.github.benmanes.caffeine.cache.stats diff --git a/dokka-cache/guru.nidi.com.kitfox/svgSalamander/1.1.3.list b/dokka-cache/guru.nidi.com.kitfox/svgSalamander/1.1.3.list new file mode 100644 index 0000000000..35698a1d34 --- /dev/null +++ b/dokka-cache/guru.nidi.com.kitfox/svgSalamander/1.1.3.list @@ -0,0 +1,13 @@ +com.kitfox.svg +com.kitfox.svg.animation +com.kitfox.svg.animation.parser +com.kitfox.svg.app +com.kitfox.svg.app.ant +com.kitfox.svg.app.beans +com.kitfox.svg.app.data +com.kitfox.svg.composite +com.kitfox.svg.pathcmd +com.kitfox.svg.pattern +com.kitfox.svg.util +com.kitfox.svg.xml +com.kitfox.svg.xml.cpx diff --git a/dokka-cache/org.danilopianini/conrec/0.1.1.list b/dokka-cache/org.danilopianini/conrec/0.1.1.list new file mode 100644 index 0000000000..55d3475f3d --- /dev/null +++ b/dokka-cache/org.danilopianini/conrec/0.1.1.list @@ -0,0 +1 @@ +conrec From 032ccc1c71a674ef6618a1b8f82dfb6cbc4e20cd Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 13:01:45 +0000 Subject: [PATCH 064/196] chore(build): update the javadoc.io cache --- .../caffeine/3.2.3.list | 3 + .../alchemist-cognitive-agents/42.3.34.list | 585 ------------------ 2 files changed, 3 insertions(+), 585 deletions(-) create mode 100644 dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list diff --git a/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list b/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list new file mode 100644 index 0000000000..ae20519915 --- /dev/null +++ b/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list @@ -0,0 +1,3 @@ +module:com.github.benmanes.caffeine +com.github.benmanes.caffeine.cache +com.github.benmanes.caffeine.cache.stats diff --git a/dokka-cache/it.unibo.alchemist/alchemist-cognitive-agents/42.3.34.list b/dokka-cache/it.unibo.alchemist/alchemist-cognitive-agents/42.3.34.list index 34d7d9b3e7..e69de29bb2 100644 --- a/dokka-cache/it.unibo.alchemist/alchemist-cognitive-agents/42.3.34.list +++ b/dokka-cache/it.unibo.alchemist/alchemist-cognitive-agents/42.3.34.list @@ -1,585 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:it.unibo.alchemist.model.cognitive.actions////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractGroupSteeringAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-group-steering-action/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractGroupSteeringAction/AbstractGroupSteeringAction/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-group-steering-action/-abstract-group-steering-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractLayerAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-layer-action/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractLayerAction/AbstractLayerAction/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]#it.unibo.alchemist.model.cognitive.PedestrianProperty[kotlin.Number]#it.unibo.alchemist.model.Molecule/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-layer-action/-abstract-layer-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractLayerAction/cloneAction/#it.unibo.alchemist.model.Node[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-layer-action/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/AbstractNavigationAction/#it.unibo.alchemist.model.environments.EnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]])]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]]),TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/-abstract-navigation-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/currentRoom/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/current-room.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/desiredPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/desired-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/doorsInSight/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/doors-in-sight.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/environment.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/moveToFinal/#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/move-to-final.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/navigatingNode/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/navigating-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/pedestrianPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/pedestrian-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/update/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/update.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction/AbstractSteeringAction/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/-abstract-steering-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction/getNextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/get-next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction/maxWalk/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/max-walk.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringActionWithTarget///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action-with-target/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringActionWithTarget/AbstractSteeringActionWithTarget/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action-with-target/-abstract-steering-action-with-target.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringActionWithTarget/AbstractSteeringActionWithTarget/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.movestrategies.TargetSelectionStrategy[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action-with-target/-abstract-steering-action-with-target.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringActionWithTarget/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action-with-target/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringActionWithTarget/target/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action-with-target/target.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentArrive///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-arrive/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentArrive/CognitiveAgentArrive/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-arrive/-cognitive-agent-arrive.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentArrive/CognitiveAgentArrive/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-arrive/-cognitive-agent-arrive.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentArrive/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-arrive/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentArrive/maxWalk/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-arrive/max-walk.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentAvoidLayer///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-avoid-layer/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentAvoidLayer/CognitiveAgentAvoidLayer/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]#it.unibo.alchemist.model.cognitive.PedestrianProperty[kotlin.Number]#it.unibo.alchemist.model.Molecule#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-avoid-layer/-cognitive-agent-avoid-layer.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentAvoidLayer/cloneAction/#it.unibo.alchemist.model.Node[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-avoid-layer/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentAvoidLayer/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-avoid-layer/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCohesion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-cohesion/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCohesion/CognitiveAgentCohesion/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-cohesion/-cognitive-agent-cohesion.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCohesion/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-cohesion/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCohesion/group/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-cohesion/group.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCohesion/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-cohesion/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCombineSteering///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-combine-steering/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCombineSteering/CognitiveAgentCombineSteering/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]]#it.unibo.alchemist.model.cognitive.SteeringStrategy[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-combine-steering/-cognitive-agent-combine-steering.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCombineSteering/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-combine-steering/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCombineSteering/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-combine-steering/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentExplore///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-explore/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentExplore/CognitiveAgentExplore/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-explore/-cognitive-agent-explore.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFlee///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-flee/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFlee/CognitiveAgentFlee/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-flee/-cognitive-agent-flee.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFlee/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-flee/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFlee/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-flee/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowLayer///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-layer/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowLayer/CognitiveAgentFollowLayer/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]#it.unibo.alchemist.model.cognitive.PedestrianProperty[kotlin.Number]#it.unibo.alchemist.model.Molecule/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-layer/-cognitive-agent-follow-layer.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowLayer/cloneAction/#it.unibo.alchemist.model.Node[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-layer/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowLayer/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-layer/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowRoute///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-route/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowRoute/CognitiveAgentFollowRoute/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-route/-cognitive-agent-follow-route.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowScalarField///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-scalar-field/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowScalarField/CognitiveAgentFollowScalarField/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]])?#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]]),kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-scalar-field/-cognitive-agent-follow-scalar-field.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowScalarField/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-scalar-field/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowScalarField/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-scalar-field/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentGoalOrientedExplore///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-goal-oriented-explore/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentGoalOrientedExplore/CognitiveAgentGoalOrientedExplore/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-goal-oriented-explore/-cognitive-agent-goal-oriented-explore.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/-companion/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D.Companion/DEFAULT_WALL_REPULSION_FACTOR/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/-companion/-d-e-f-a-u-l-t_-w-a-l-l_-r-e-p-u-l-s-i-o-n_-f-a-c-t-o-r.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D/CognitiveAgentNavigationAction2D/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/-cognitive-agent-navigation-action2-d.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D/crossDoor/#it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/cross-door.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/environment.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentObstacleAvoidance///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-obstacle-avoidance/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentObstacleAvoidance/CognitiveAgentObstacleAvoidance/#it.unibo.alchemist.model.environments.Environment2DWithObstacles[TypeParam(bounds=[it.unibo.alchemist.model.Obstacle2D[it.unibo.alchemist.model.positions.Euclidean2DPosition]]),TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.reactions.SteeringBehavior[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-obstacle-avoidance/-cognitive-agent-obstacle-avoidance.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentObstacleAvoidance/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-obstacle-avoidance/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentObstacleAvoidance/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-obstacle-avoidance/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentPursue///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-pursue/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentPursue/CognitiveAgentPursue/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-pursue/-cognitive-agent-pursue.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentReachDestination///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-reach-destination/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentReachDestination/CognitiveAgentReachDestination/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-reach-destination/-cognitive-agent-reach-destination.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentReachKnownDestination///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-reach-known-destination/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentReachKnownDestination/CognitiveAgentReachKnownDestination/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-reach-known-destination/-cognitive-agent-reach-known-destination.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek/CognitiveAgentSeek/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek/-cognitive-agent-seek.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek/CognitiveAgentSeek/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek/-cognitive-agent-seek.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D/CognitiveAgentSeek2D/#it.unibo.alchemist.model.EuclideanEnvironment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/-cognitive-agent-seek2-d.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D/CognitiveAgentSeek2D/#it.unibo.alchemist.model.EuclideanEnvironment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/-cognitive-agent-seek2-d.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D/target/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/target.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation/CognitiveAgentSeparation/#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/-cognitive-agent-separation.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/environment.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation/group/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/group.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentWander///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-wander/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentWander/CognitiveAgentWander/#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#org.apache.commons.math3.random.RandomGenerator#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-wander/-cognitive-agent-wander.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentWander/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-wander/clone-action.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentWander/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-wander/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.actions/NavigationAction2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-navigation-action2-d/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.conditions////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/WantToEscape/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/-want-to-escape.html -$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/context/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/context.html -$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/getContext/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/get-context.html -$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/getPropensityContribution/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/get-propensity-contribution.html -$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/isValid/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/is-valid.html -$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/propensityContribution/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/propensity-contribution.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/EnvironmentWithDynamics/#it.unibo.alchemist.model.Incarnation[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]#kotlin.String?#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Int#kotlin.Int#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/-environment-with-dynamics.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/addGlobalReaction/#it.unibo.alchemist.model.GlobalReaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/add-global-reaction.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/addNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/add-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/getPosition/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/get-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/getVelocity/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/get-velocity.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/makePosition/#kotlin.DoubleArray/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/make-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/makePosition/#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/make-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/makePosition/#kotlin.collections.List[kotlin.Number]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/make-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/moveNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/move-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/origin/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/origin.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/setVelocity/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/set-velocity.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/updatePhysics/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/update-physics.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/ImageEnvironmentWithGraph///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-image-environment-with-graph/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/ImageEnvironmentWithGraph/ImageEnvironmentWithGraph/#it.unibo.alchemist.model.Incarnation[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]#kotlin.String#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Int#kotlin.Int/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-image-environment-with-graph/-image-environment-with-graph.html -$dokka.location:it.unibo.alchemist.model.cognitive.environments/ImageEnvironmentWithGraph/graph/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-image-environment-with-graph/graph.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/Alone///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-alone/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/Alone/Alone/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-alone/-alone.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/Family///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-family/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/Family/Family/#java.util.Comparator[it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-family/-family.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/Family/leader/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-family/leader.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/Friends///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-friends/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/Friends/Friends/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-friends/-friends.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/GenericGroup///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-generic-group/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/GenericGroup/GenericGroup/#kotlin.collections.List[TypeParam(bounds=[it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-generic-group/-generic-group.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/GenericGroup/addMember/#TypeParam(bounds=[it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-generic-group/add-member.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/GenericGroup/removeMember/#TypeParam(bounds=[it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-generic-group/remove-member.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/GroupFactory///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-group-factory/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/GroupFactory/family/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-group-factory/family.html -$dokka.location:it.unibo.alchemist.model.cognitive.groups/GroupFactory/friends/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-group-factory/friends.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/advancedLogisticSigma/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/advanced-logistic-sigma.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/advancedLogisticTau/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/advanced-logistic-tau.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/affectiveBiasingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/affective-biasing-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/amplifyingEvacuationOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/amplifying-evacuation-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/amplifyingFeelingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/amplifying-feeling-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/amplifyingIntentionOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/amplifying-intention-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/bodyEta/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/body-eta.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/inhibitingFeelingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/inhibiting-feeling-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/inhibitingIntentionOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/inhibiting-intention-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/inhibitingWalkRandOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/inhibiting-walk-rand-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/logisticSigma/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/logistic-sigma.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/logisticTau/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/logistic-tau.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/mentalEta/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/mental-eta.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/persistingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/persisting-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/sensingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/sensing-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic/AbstractCognitiveCharacteristic/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-abstract-cognitive-characteristic.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/combination-function.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic/level/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/level.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BeliefDanger///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-belief-danger/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BeliefDanger/BeliefDanger/#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.collections.List[it.unibo.alchemist.model.cognitive.CognitiveModel]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-belief-danger/-belief-danger.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BeliefDanger/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-belief-danger/combination-function.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BodyCognitiveCharacteristic///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-body-cognitive-characteristic/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BodyCognitiveCharacteristic/BodyCognitiveCharacteristic/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-body-cognitive-characteristic/-body-cognitive-characteristic.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BodyCognitiveCharacteristic/update/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-body-cognitive-characteristic/update.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveCharacteristic///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-characteristic/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveCharacteristic/level/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-characteristic/level.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveCharacteristic/update/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-characteristic/update.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/advancedLogisticSigma/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/advanced-logistic-sigma.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/advancedLogisticTau/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/advanced-logistic-tau.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/affectiveBiasingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/affective-biasing-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/amplifyingEvacuationOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/amplifying-evacuation-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/amplifyingFeelingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/amplifying-feeling-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/amplifyingIntentionOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/amplifying-intention-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/bodyEta/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/body-eta.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/inhibitingFeelingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/inhibiting-feeling-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/inhibitingIntentionOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/inhibiting-intention-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/inhibitingWalkRandOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/inhibiting-walk-rand-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/logisticSigma/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/logistic-sigma.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/logisticTau/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/logistic-tau.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/mentalEta/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/mental-eta.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/persistingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/persisting-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/sensingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/sensing-omega.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireEvacuate///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-evacuate/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireEvacuate/DesireEvacuate/#kotlin.Double#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-evacuate/-desire-evacuate.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireEvacuate/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-evacuate/combination-function.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireWalkRandomly///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-walk-randomly/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireWalkRandomly/DesireWalkRandomly/#kotlin.Double#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-walk-randomly/-desire-walk-randomly.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireWalkRandomly/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-walk-randomly/combination-function.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/Fear///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-fear/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/Fear/Fear/#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.collections.List[it.unibo.alchemist.model.cognitive.CognitiveModel]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-fear/-fear.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/Fear/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-fear/combination-function.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionEvacuate///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-evacuate/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionEvacuate/IntentionEvacuate/#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-evacuate/-intention-evacuate.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionEvacuate/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-evacuate/combination-function.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionWalkRandomly///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-walk-randomly/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionWalkRandomly/IntentionWalkRandomly/#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-walk-randomly/-intention-walk-randomly.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionWalkRandomly/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-walk-randomly/combination-function.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/MentalCognitiveCharacteristic///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-mental-cognitive-characteristic/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/MentalCognitiveCharacteristic/MentalCognitiveCharacteristic/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-mental-cognitive-characteristic/-mental-cognitive-characteristic.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/MentalCognitiveCharacteristic/update/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-mental-cognitive-characteristic/update.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.ADULT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-a-d-u-l-t/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.CHILD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-c-h-i-l-d/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion/ADULT_THRESHOLD/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/-a-d-u-l-t_-t-h-r-e-s-h-o-l-d.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion/CHILD_THRESHOLD/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/-c-h-i-l-d_-t-h-r-e-s-h-o-l-d.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion/fromAny/#kotlin.Any/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/from-any.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion/fromString/#kotlin.String/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/from-string.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion/fromYears/#kotlin.Int/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/from-years.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.ELDERLY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-e-l-d-e-r-l-y/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age/entries/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/entries.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age/valueOf/#kotlin.String/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/value-of.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age/values/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/values.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Characteristic///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-characteristic/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Compliance///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Compliance/Compliance/#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance/-compliance.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Compliance/level/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance/level.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/adult-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/adult-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/child-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/child-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/elderly-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/elderly-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/-companion/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender.Companion/fromString/#kotlin.String/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/-companion/from-string.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender.FEMALE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/-f-e-m-a-l-e/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender.MALE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/-m-a-l-e/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender/entries/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/entries.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender/valueOf/#kotlin.String/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/value-of.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender/values/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/values.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitude///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitude/HelpAttitude/#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude/-help-attitude.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitude/level/#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender#kotlin.Boolean/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude/level.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/adult-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/adult-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/child-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/child-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/elderly-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/elderly-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/adult-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/adult-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/child-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/child-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/elderly-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/elderly-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/adult-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/adult-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/child-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/child-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/elderly-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/elderly-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/adult-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/adult-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/child-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/child-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/elderly-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/elderly-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/-companion/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed.Companion/default/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/-companion/default.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed/Speed/#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender#org.apache.commons.math3.random.RandomGenerator/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/-speed.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed/running/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/running.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed/walking/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/walking.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/adult-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/adult-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/child-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/child-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/default/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/default.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/elderly-female.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/elderly-male.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/variance/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/variance.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact//PARAMETERS_FILE/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-p-a-r-a-m-e-t-e-r-s_-f-i-l-e.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/ImpactModel/#kotlin.Double#kotlin.Function0[kotlin.collections.List[it.unibo.alchemist.model.cognitive.CognitiveModel]]#kotlin.Function0[kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/-impact-model.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/dangerBelief/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/danger-belief.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/escapeIntention/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/escape-intention.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/fear/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/fear.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/remainIntention/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/remain-intention.html -$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/update/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/update.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/DynamicallyPursue///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-dynamically-pursue/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/DynamicallyPursue/DynamicallyPursue/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-dynamically-pursue/-dynamically-pursue.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/DynamicallyPursue/setDestination/#it.unibo.alchemist.model.positions.Euclidean2DPosition#kotlin.Boolean/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-dynamically-pursue/set-destination.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/-companion/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore.Companion/DEFAULT_IMPASSE_WEIGHT/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/-companion/-d-e-f-a-u-l-t_-i-m-p-a-s-s-e_-w-e-i-g-h-t.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore/Explore/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/-explore.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore/action/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/action.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore/inNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/in-new-room.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/FollowRoute///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-follow-route/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/FollowRoute/FollowRoute/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-follow-route/-follow-route.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/FollowRoute/inNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-follow-route/in-new-room.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/FollowRoute/inUnexpectedNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon#it.unibo.alchemist.model.geometry.ConvexPolygon#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-follow-route/in-unexpected-new-room.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/GoalOrientedExploration///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-goal-oriented-exploration/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/GoalOrientedExploration/GoalOrientedExploration/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-goal-oriented-exploration/-goal-oriented-exploration.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/GoalOrientedExploration/inNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-goal-oriented-exploration/in-new-room.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Pursue///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-pursue/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Pursue/Pursue/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-pursue/-pursue.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Pursue/inNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-pursue/in-new-room.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/ReachDestination///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-reach-destination/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/ReachDestination/ReachDestination/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-reach-destination/-reach-destination.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/ReachDestination/inNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-reach-destination/in-new-room.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/ReachKnownDestination///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-reach-known-destination/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.navigation/ReachKnownDestination/ReachKnownDestination/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-reach-known-destination/-reach-known-destination.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/Cognitive/#it.unibo.alchemist.model.physics.PhysicsEnvironment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]])]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.GeometricShapeFactory[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Molecule?/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/-cognitive.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/cognitiveModel/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/cognitive-model.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/danger/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/danger.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/to-string.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive2-d/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive2D/Cognitive2D/#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Molecule?/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive2-d/-cognitive2-d.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/CognitivePedestrian///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive-pedestrian/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/CognitivePedestrian/CognitivePedestrian/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive-pedestrian/-cognitive-pedestrian.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/CognitivePedestrian/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive-pedestrian/speed.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/HeterogeneousPedestrian///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-heterogeneous-pedestrian/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/HeterogeneousPedestrian/HeterogeneousPedestrian/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-heterogeneous-pedestrian/-heterogeneous-pedestrian.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/HeterogeneousPedestrian/runningSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-heterogeneous-pedestrian/running-speed.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/HeterogeneousPedestrian/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-heterogeneous-pedestrian/to-string.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/HeterogeneousPedestrian/walkingSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-heterogeneous-pedestrian/walking-speed.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/Human/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender#it.unibo.alchemist.model.cognitive.impact.individual.Speed#kotlin.Double#it.unibo.alchemist.model.cognitive.impact.individual.HelpAttitude/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/-human.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/Human/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Any#kotlin.String#it.unibo.alchemist.model.cognitive.impact.individual.Speed#kotlin.Double#it.unibo.alchemist.model.cognitive.impact.individual.HelpAttitude/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/-human.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/age/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/age.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/compliance/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/compliance.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/gender/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/gender.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/helpAttitude/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/help-attitude.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/speed.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/to-string.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/-companion/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting.Companion/pathExists/org.jgrapht.Graph[TypeParam(bounds=[kotlin.Any?]),*]#TypeParam(bounds=[kotlin.Any?])#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/-companion/path-exists.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/Orienting/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.environments.EnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]])]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]]),org.jgrapht.graph.DefaultEdge]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/-orienting.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/cognitiveMap/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/cognitive-map.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/createLandmarkIn/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/create-landmark-in.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/environment.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/knowledgeDegree/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/knowledge-degree.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/randomGenerator/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/random-generator.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/to-string.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/volatileMemory/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/volatile-memory.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/Orienting2D/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon]),org.jgrapht.graph.DefaultEdge]#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/-orienting2-d.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/createLandmarkIn/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/create-landmark-in.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/environment.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/knowledgeDegree/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/knowledge-degree.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/Pedestrian/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/-pedestrian.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/runningSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/running-speed.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/speed.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/to-string.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/walkingSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/walking-speed.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive/Perceptive/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.physics.InfluenceSphere[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive/-perceptive.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive/fieldOfView/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive/field-of-view.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/-companion/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D.Companion/DEFAULT_FIELD_OF_VIEW_APERTURE/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/-companion/-d-e-f-a-u-l-t_-f-i-e-l-d_-o-f_-v-i-e-w_-a-p-e-r-t-u-r-e.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D.Companion/DEFAULT_FIELD_OF_VIEW_DEPTH/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/-companion/-d-e-f-a-u-l-t_-f-i-e-l-d_-o-f_-v-i-e-w_-d-e-p-t-h.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D/Perceptive2D/#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.physics.InfluenceSphere2D[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/-perceptive2-d.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/environment.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D/fieldOfView/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/field-of-view.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/PhysicalPedestrian2D/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/-physical-pedestrian2-d.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/avoid/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/avoid.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/avoidanceForces/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/avoidance-forces.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/checkAndPossiblyFall/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/check-and-possibly-fall.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/comfortArea/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/comfort-area.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/comfortRay/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/comfort-ray.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/environment.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/fallenAgentAvoidanceForces/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/fallen-agent-avoidance-forces.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/isFallen/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/is-fallen.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/onFall/#kotlin.Function1[it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])],kotlin.Unit]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/on-fall.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/physicalForces/#it.unibo.alchemist.model.physics.PhysicsEnvironment[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,it.unibo.alchemist.model.geometry.Euclidean2DShapeFactory]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/physical-forces.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/rectangleOfInfluence/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/rectangle-of-influence.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/repulse/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/repulse.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/repulsionForces/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/repulsion-forces.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/shouldFall/#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/should-fall.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/to-string.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/RunningPedestrian///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-running-pedestrian/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/RunningPedestrian/RunningPedestrian/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-running-pedestrian/-running-pedestrian.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/RunningPedestrian/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-running-pedestrian/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/RunningPedestrian/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-running-pedestrian/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/RunningPedestrian/runningSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-running-pedestrian/running-speed.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social/Social/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.Group[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/-social.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social/group/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/group.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/to-string.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/WalkingPedestrian///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-walking-pedestrian/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/WalkingPedestrian/WalkingPedestrian/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-walking-pedestrian/-walking-pedestrian.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/WalkingPedestrian/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-walking-pedestrian/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/WalkingPedestrian/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-walking-pedestrian/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.properties/WalkingPedestrian/walkingSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-walking-pedestrian/walking-speed.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/BlendedSteering///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-blended-steering/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/BlendedSteering/BlendedSteering/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-blended-steering/-blended-steering.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/CognitiveBehavior///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-cognitive-behavior/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/CognitiveBehavior/CognitiveBehavior/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-cognitive-behavior/-cognitive-behavior.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/CognitiveBehavior/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-cognitive-behavior/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/NavigationPrioritizedSteering///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-navigation-prioritized-steering/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/NavigationPrioritizedSteering/NavigationPrioritizedSteering/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon]),*]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-navigation-prioritized-steering/-navigation-prioritized-steering.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/NavigationPrioritizedSteeringWithPhysics///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-navigation-prioritized-steering-with-physics/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/NavigationPrioritizedSteeringWithPhysics/NavigationPrioritizedSteeringWithPhysics/#it.unibo.alchemist.model.physics.environments.EuclideanPhysics2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon]),*]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-navigation-prioritized-steering-with-physics/-navigation-prioritized-steering-with-physics.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/NavigationPrioritizedSteeringWithPhysics/steerStrategy/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-navigation-prioritized-steering-with-physics/steer-strategy.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PhysicalBlendedSteering///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-physical-blended-steering/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PhysicalBlendedSteering/PhysicalBlendedSteering/#it.unibo.alchemist.model.physics.environments.Dynamics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-physical-blended-steering/-physical-blended-steering.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PhysicalBlendedSteering/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-physical-blended-steering/environment.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PhysicalBlendedSteering/execute/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-physical-blended-steering/execute.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PhysicalBlendedSteering/steerStrategy/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-physical-blended-steering/steer-strategy.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PrioritySteering///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-priority-steering/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PrioritySteering/PrioritySteering/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-priority-steering/-priority-steering.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior/SteeringBehavior/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.SteeringStrategy[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/-steering-behavior.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/clone-on-new-node.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior/execute/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/execute.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior/steerActions/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/steer-actions.html -$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior/steerStrategy/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/steer-strategy.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/DistanceWeighted///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-distance-weighted/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/DistanceWeighted/DistanceWeighted/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-distance-weighted/-distance-weighted.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Filtered///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-filtered/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Filtered/Filtered/#it.unibo.alchemist.model.cognitive.SteeringStrategy[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#kotlin.Function1[kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]],kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-filtered/-filtered.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Filtered/computeNextPosition/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-filtered/compute-next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Nearest///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-nearest/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Nearest/Nearest/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-nearest/-nearest.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-companion/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent.Companion/DEFAULT_ALPHA/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-companion/-d-e-f-a-u-l-t_-a-l-p-h-a.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent.Companion/DEFAULT_DELTA/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-companion/-d-e-f-a-u-l-t_-d-e-l-t-a.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent.Companion/DEFAULT_MAX_WALK_RATIO/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-companion/-d-e-f-a-u-l-t_-m-a-x_-w-a-l-k_-r-a-t-i-o.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent.Companion/DEFAULT_TOLERANCE_ANGLE/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-companion/-d-e-f-a-u-l-t_-t-o-l-e-r-a-n-c-e_-a-n-g-l-e.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent/SinglePrevalent/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon]),*]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Function1[kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]],it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,*,*,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon]),*]]#kotlin.Double#kotlin.Double#kotlin.Function0[kotlin.Double]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-single-prevalent.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent/computeNextPosition/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/compute-next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Sum///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-sum/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Sum/Sum/#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.SteeringStrategy[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-sum/-sum.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Sum/computeNextPosition/#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-sum/compute-next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Sum/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-sum/node.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Sum/nonPhysicalStrategy/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-sum/non-physical-strategy.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/TypeBased///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-type-based/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/TypeBased/TypeBased/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#java.util.LinkedHashMap[kotlin.reflect.KClass[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]],kotlin.Double]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-type-based/-type-based.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Weighted///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-weighted/index.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Weighted/Weighted/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Function1[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition],kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-weighted/-weighted.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Weighted/computeNextPosition/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-weighted/compute-next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive.steering/Weighted/computeTarget/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-weighted/compute-target.html -$dokka.location:it.unibo.alchemist.model.cognitive////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/dangerBelief/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/danger-belief.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/escapeIntention/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/escape-intention.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/fear/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/fear.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/remainIntention/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/remain-intention.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/update/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/update.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/wantsToEscape/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/wants-to-escape.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-property/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveProperty/cognitiveModel/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-property/cognitive-model.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveProperty/danger/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-property/danger.html -$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveProperty/influentialPeople/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-property/influential-people.html -$dokka.location:it.unibo.alchemist.model.cognitive/Group///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/Group/members/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group/members.html -$dokka.location:it.unibo.alchemist.model.cognitive/GroupSteeringAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group-steering-action/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/GroupSteeringAction/group/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group-steering-action/group.html -$dokka.location:it.unibo.alchemist.model.cognitive/GroupWithLeader///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group-with-leader/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/GroupWithLeader/leader/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group-with-leader/leader.html -$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/HeterogeneousPedestrianModel/#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender#it.unibo.alchemist.model.cognitive.impact.individual.Speed#kotlin.Double#it.unibo.alchemist.model.cognitive.impact.individual.HelpAttitude/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/-heterogeneous-pedestrian-model.html -$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/age/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/age.html -$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/compliance/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/compliance.html -$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/gender/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/gender.html -$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/helpAttitude/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/help-attitude.html -$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/probabilityOfHelping/#it.unibo.alchemist.model.cognitive.HeterogeneousPedestrianModel[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^^]])]])]#kotlin.Boolean/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/probability-of-helping.html -$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/speed.html -$dokka.location:it.unibo.alchemist.model.cognitive/Human2DProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human2-d-property/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/age/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/age.html -$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/compliance/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/compliance.html -$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/gender/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/gender.html -$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/helpAttitude/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/help-attitude.html -$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/probabilityOfHelping/#it.unibo.alchemist.model.cognitive.HeterogeneousPedestrianModel[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^^]])]])]#kotlin.Boolean/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/probability-of-helping.html -$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/speed.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/crossDoor/#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/cross-door.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/currentRoom/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/current-room.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/doorsInSight/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/doors-in-sight.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/environment.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/moveToFinal/#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/move-to-final.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/navigatingNode/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/navigating-node.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/orientingProperty/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/orienting-property.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/pedestrianPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/pedestrian-position.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/stop/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/stop.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy/action/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy/action.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy/inNewRoom/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy/in-new-room.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy/inUnexpectedNewRoom/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy/in-unexpected-new-room.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy/orientingCapability/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy/orienting-capability.html -$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy2-d/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent/cognitiveMap/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent/cognitive-map.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent/knowledgeDegree/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent/knowledge-degree.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent/registerVisit/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent/register-visit.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent/volatileMemory/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent/volatile-memory.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent2-d/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/cognitiveMap/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/cognitive-map.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/createLandmarkIn/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/create-landmark-in.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/environment.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/knowledgeDegree/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/knowledge-degree.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/registerVisit/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/register-visit.html -$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/volatileMemory/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/volatile-memory.html -$dokka.location:it.unibo.alchemist.model.cognitive/PedestrianProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-pedestrian-property/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/PedestrianProperty/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-pedestrian-property/speed.html -$dokka.location:it.unibo.alchemist.model.cognitive/PerceptiveProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-perceptive-property/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/PerceptiveProperty/fieldOfView/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-perceptive-property/field-of-view.html -$dokka.location:it.unibo.alchemist.model.cognitive/PerceptiveProperty/senses/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-perceptive-property/senses.html -$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy/computeNextPosition/#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/compute-next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy/computeNextPosition/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/compute-next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy/computeTarget/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/compute-target.html -$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/node.html -$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy/nonPhysicalStrategy/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/non-physical-strategy.html -$dokka.location:it.unibo.alchemist.model.cognitive/RunningPedestrianProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-running-pedestrian-property/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/RunningPedestrianProperty/runningSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-running-pedestrian-property/running-speed.html -$dokka.location:it.unibo.alchemist.model.cognitive/SocialProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-social-property/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/SocialProperty/group/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-social-property/group.html -$dokka.location:it.unibo.alchemist.model.cognitive/SteeringAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-action/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/SteeringAction/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-action/next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive/SteeringActionWithTarget///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-action-with-target/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/SteeringActionWithTarget/target/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-action-with-target/target.html -$dokka.location:it.unibo.alchemist.model.cognitive/SteeringActionWithTarget/targetDistanceTo/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-action-with-target/target-distance-to.html -$dokka.location:it.unibo.alchemist.model.cognitive/SteeringStrategy///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-strategy/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/SteeringStrategy/computeNextPosition/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-strategy/compute-next-position.html -$dokka.location:it.unibo.alchemist.model.cognitive/SteeringStrategy/computeTarget/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-strategy/compute-target.html -$dokka.location:it.unibo.alchemist.model.cognitive/WalkingPedestrianProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-walking-pedestrian-property/index.html -$dokka.location:it.unibo.alchemist.model.cognitive/WalkingPedestrianProperty/walkingSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-walking-pedestrian-property/walking-speed.html -$dokka.location:it.unibo.alchemist.util////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/index.html -$dokka.location:it.unibo.alchemist.util//lazyMutable/#kotlin.Function0[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/lazy-mutable.html -$dokka.location:it.unibo.alchemist.util/LazyMutable///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/-lazy-mutable/index.html -$dokka.location:it.unibo.alchemist.util/LazyMutable/LazyMutable/#kotlin.Function0[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/-lazy-mutable/-lazy-mutable.html -$dokka.location:it.unibo.alchemist.util/LazyMutable/getValue/#kotlin.Any?#kotlin.reflect.KProperty[*]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/-lazy-mutable/get-value.html -$dokka.location:it.unibo.alchemist.util/LazyMutable/setValue/#kotlin.Any?#kotlin.reflect.KProperty[*]#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/-lazy-mutable/set-value.html -it.unibo.alchemist.model.cognitive -it.unibo.alchemist.model.cognitive.actions -it.unibo.alchemist.model.cognitive.conditions -it.unibo.alchemist.model.cognitive.environments -it.unibo.alchemist.model.cognitive.groups -it.unibo.alchemist.model.cognitive.impact -it.unibo.alchemist.model.cognitive.impact.cognitive -it.unibo.alchemist.model.cognitive.impact.individual -it.unibo.alchemist.model.cognitive.navigation -it.unibo.alchemist.model.cognitive.properties -it.unibo.alchemist.model.cognitive.reactions -it.unibo.alchemist.model.cognitive.steering -it.unibo.alchemist.util From 24a9e525d8d83e9d1999d4e1dc2795c13166e325 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 13:22:47 +0000 Subject: [PATCH 065/196] chore(build): update the javadoc.io cache --- .../alchemist-cognitive-agents/42.3.18.list | 585 ++++++++++++++++++ dokka-cache/org.jooq/jool/0.9.15.list | 9 - 2 files changed, 585 insertions(+), 9 deletions(-) create mode 100644 dokka-cache/it.unibo.alchemist/alchemist-cognitive-agents/42.3.18.list delete mode 100644 dokka-cache/org.jooq/jool/0.9.15.list diff --git a/dokka-cache/it.unibo.alchemist/alchemist-cognitive-agents/42.3.18.list b/dokka-cache/it.unibo.alchemist/alchemist-cognitive-agents/42.3.18.list new file mode 100644 index 0000000000..34d7d9b3e7 --- /dev/null +++ b/dokka-cache/it.unibo.alchemist/alchemist-cognitive-agents/42.3.18.list @@ -0,0 +1,585 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:it.unibo.alchemist.model.cognitive.actions////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractGroupSteeringAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-group-steering-action/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractGroupSteeringAction/AbstractGroupSteeringAction/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-group-steering-action/-abstract-group-steering-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractLayerAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-layer-action/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractLayerAction/AbstractLayerAction/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]#it.unibo.alchemist.model.cognitive.PedestrianProperty[kotlin.Number]#it.unibo.alchemist.model.Molecule/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-layer-action/-abstract-layer-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractLayerAction/cloneAction/#it.unibo.alchemist.model.Node[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-layer-action/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/AbstractNavigationAction/#it.unibo.alchemist.model.environments.EnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]])]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]]),TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/-abstract-navigation-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/currentRoom/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/current-room.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/desiredPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/desired-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/doorsInSight/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/doors-in-sight.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/environment.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/moveToFinal/#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/move-to-final.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/navigatingNode/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/navigating-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/pedestrianPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/pedestrian-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractNavigationAction/update/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-navigation-action/update.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction/AbstractSteeringAction/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/-abstract-steering-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction/getNextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/get-next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction/maxWalk/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/max-walk.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringAction/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringActionWithTarget///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action-with-target/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringActionWithTarget/AbstractSteeringActionWithTarget/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action-with-target/-abstract-steering-action-with-target.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringActionWithTarget/AbstractSteeringActionWithTarget/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.movestrategies.TargetSelectionStrategy[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action-with-target/-abstract-steering-action-with-target.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringActionWithTarget/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action-with-target/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/AbstractSteeringActionWithTarget/target/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-abstract-steering-action-with-target/target.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentArrive///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-arrive/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentArrive/CognitiveAgentArrive/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-arrive/-cognitive-agent-arrive.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentArrive/CognitiveAgentArrive/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-arrive/-cognitive-agent-arrive.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentArrive/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-arrive/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentArrive/maxWalk/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-arrive/max-walk.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentAvoidLayer///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-avoid-layer/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentAvoidLayer/CognitiveAgentAvoidLayer/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]#it.unibo.alchemist.model.cognitive.PedestrianProperty[kotlin.Number]#it.unibo.alchemist.model.Molecule#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-avoid-layer/-cognitive-agent-avoid-layer.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentAvoidLayer/cloneAction/#it.unibo.alchemist.model.Node[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-avoid-layer/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentAvoidLayer/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-avoid-layer/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCohesion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-cohesion/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCohesion/CognitiveAgentCohesion/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-cohesion/-cognitive-agent-cohesion.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCohesion/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-cohesion/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCohesion/group/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-cohesion/group.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCohesion/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-cohesion/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCombineSteering///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-combine-steering/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCombineSteering/CognitiveAgentCombineSteering/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]]#it.unibo.alchemist.model.cognitive.SteeringStrategy[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-combine-steering/-cognitive-agent-combine-steering.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCombineSteering/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-combine-steering/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentCombineSteering/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-combine-steering/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentExplore///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-explore/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentExplore/CognitiveAgentExplore/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-explore/-cognitive-agent-explore.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFlee///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-flee/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFlee/CognitiveAgentFlee/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-flee/-cognitive-agent-flee.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFlee/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-flee/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFlee/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-flee/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowLayer///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-layer/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowLayer/CognitiveAgentFollowLayer/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]#it.unibo.alchemist.model.cognitive.PedestrianProperty[kotlin.Number]#it.unibo.alchemist.model.Molecule/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-layer/-cognitive-agent-follow-layer.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowLayer/cloneAction/#it.unibo.alchemist.model.Node[kotlin.Number]#it.unibo.alchemist.model.Reaction[kotlin.Number]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-layer/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowLayer/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-layer/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowRoute///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-route/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowRoute/CognitiveAgentFollowRoute/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-route/-cognitive-agent-follow-route.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowScalarField///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-scalar-field/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowScalarField/CognitiveAgentFollowScalarField/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]])?#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]]),kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-scalar-field/-cognitive-agent-follow-scalar-field.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowScalarField/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-scalar-field/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentFollowScalarField/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-follow-scalar-field/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentGoalOrientedExplore///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-goal-oriented-explore/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentGoalOrientedExplore/CognitiveAgentGoalOrientedExplore/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-goal-oriented-explore/-cognitive-agent-goal-oriented-explore.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/-companion/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D.Companion/DEFAULT_WALL_REPULSION_FACTOR/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/-companion/-d-e-f-a-u-l-t_-w-a-l-l_-r-e-p-u-l-s-i-o-n_-f-a-c-t-o-r.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D/CognitiveAgentNavigationAction2D/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/-cognitive-agent-navigation-action2-d.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D/crossDoor/#it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/cross-door.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/environment.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentNavigationAction2D/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-navigation-action2-d/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentObstacleAvoidance///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-obstacle-avoidance/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentObstacleAvoidance/CognitiveAgentObstacleAvoidance/#it.unibo.alchemist.model.environments.Environment2DWithObstacles[TypeParam(bounds=[it.unibo.alchemist.model.Obstacle2D[it.unibo.alchemist.model.positions.Euclidean2DPosition]]),TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.reactions.SteeringBehavior[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-obstacle-avoidance/-cognitive-agent-obstacle-avoidance.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentObstacleAvoidance/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-obstacle-avoidance/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentObstacleAvoidance/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-obstacle-avoidance/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentPursue///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-pursue/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentPursue/CognitiveAgentPursue/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-pursue/-cognitive-agent-pursue.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentReachDestination///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-reach-destination/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentReachDestination/CognitiveAgentReachDestination/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-reach-destination/-cognitive-agent-reach-destination.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentReachKnownDestination///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-reach-known-destination/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentReachKnownDestination/CognitiveAgentReachKnownDestination/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-reach-known-destination/-cognitive-agent-reach-known-destination.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek/CognitiveAgentSeek/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek/-cognitive-agent-seek.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek/CognitiveAgentSeek/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek/-cognitive-agent-seek.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D/CognitiveAgentSeek2D/#it.unibo.alchemist.model.EuclideanEnvironment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/-cognitive-agent-seek2-d.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D/CognitiveAgentSeek2D/#it.unibo.alchemist.model.EuclideanEnvironment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^], it.unibo.alchemist.model.geometry.Vector2D[^]])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#kotlin.Number#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/-cognitive-agent-seek2-d.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeek2D/target/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-seek2-d/target.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation/CognitiveAgentSeparation/#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/-cognitive-agent-separation.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/environment.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation/group/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/group.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentSeparation/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-separation/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentWander///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-wander/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentWander/CognitiveAgentWander/#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#org.apache.commons.math3.random.RandomGenerator#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-wander/-cognitive-agent-wander.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentWander/cloneAction/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-wander/clone-action.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/CognitiveAgentWander/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-cognitive-agent-wander/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.actions/NavigationAction2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.actions/-navigation-action2-d/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.conditions////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/WantToEscape/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/-want-to-escape.html +$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/context/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/context.html +$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/getContext/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/get-context.html +$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/getPropensityContribution/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/get-propensity-contribution.html +$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/isValid/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/is-valid.html +$dokka.location:it.unibo.alchemist.model.cognitive.conditions/WantToEscape/propensityContribution/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.conditions/-want-to-escape/propensity-contribution.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/EnvironmentWithDynamics/#it.unibo.alchemist.model.Incarnation[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]#kotlin.String?#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Int#kotlin.Int#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/-environment-with-dynamics.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/addGlobalReaction/#it.unibo.alchemist.model.GlobalReaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/add-global-reaction.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/addNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/add-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/getPosition/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/get-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/getVelocity/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/get-velocity.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/makePosition/#kotlin.DoubleArray/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/make-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/makePosition/#kotlin.Number/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/make-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/makePosition/#kotlin.collections.List[kotlin.Number]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/make-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/moveNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/move-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/origin/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/origin.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/setVelocity/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/set-velocity.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/EnvironmentWithDynamics/updatePhysics/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-environment-with-dynamics/update-physics.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/ImageEnvironmentWithGraph///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-image-environment-with-graph/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/ImageEnvironmentWithGraph/ImageEnvironmentWithGraph/#it.unibo.alchemist.model.Incarnation[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]#kotlin.String#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Int#kotlin.Int/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-image-environment-with-graph/-image-environment-with-graph.html +$dokka.location:it.unibo.alchemist.model.cognitive.environments/ImageEnvironmentWithGraph/graph/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.environments/-image-environment-with-graph/graph.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/Alone///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-alone/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/Alone/Alone/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-alone/-alone.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/Family///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-family/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/Family/Family/#java.util.Comparator[it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-family/-family.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/Family/leader/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-family/leader.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/Friends///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-friends/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/Friends/Friends/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-friends/-friends.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/GenericGroup///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-generic-group/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/GenericGroup/GenericGroup/#kotlin.collections.List[TypeParam(bounds=[it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-generic-group/-generic-group.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/GenericGroup/addMember/#TypeParam(bounds=[it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-generic-group/add-member.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/GenericGroup/removeMember/#TypeParam(bounds=[it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-generic-group/remove-member.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/GroupFactory///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-group-factory/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/GroupFactory/family/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-group-factory/family.html +$dokka.location:it.unibo.alchemist.model.cognitive.groups/GroupFactory/friends/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.groups/-group-factory/friends.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/advancedLogisticSigma/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/advanced-logistic-sigma.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/advancedLogisticTau/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/advanced-logistic-tau.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/affectiveBiasingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/affective-biasing-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/amplifyingEvacuationOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/amplifying-evacuation-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/amplifyingFeelingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/amplifying-feeling-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/amplifyingIntentionOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/amplifying-intention-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/bodyEta/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/body-eta.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/inhibitingFeelingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/inhibiting-feeling-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/inhibitingIntentionOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/inhibiting-intention-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/inhibitingWalkRandOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/inhibiting-walk-rand-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/logisticSigma/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/logistic-sigma.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/logisticTau/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/logistic-tau.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/mentalEta/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/mental-eta.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/persistingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/persisting-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic.Companion/sensingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-companion/sensing-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic/AbstractCognitiveCharacteristic/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/-abstract-cognitive-characteristic.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/combination-function.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/AbstractCognitiveCharacteristic/level/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-abstract-cognitive-characteristic/level.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BeliefDanger///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-belief-danger/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BeliefDanger/BeliefDanger/#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.collections.List[it.unibo.alchemist.model.cognitive.CognitiveModel]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-belief-danger/-belief-danger.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BeliefDanger/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-belief-danger/combination-function.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BodyCognitiveCharacteristic///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-body-cognitive-characteristic/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BodyCognitiveCharacteristic/BodyCognitiveCharacteristic/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-body-cognitive-characteristic/-body-cognitive-characteristic.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/BodyCognitiveCharacteristic/update/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-body-cognitive-characteristic/update.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveCharacteristic///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-characteristic/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveCharacteristic/level/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-characteristic/level.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveCharacteristic/update/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-characteristic/update.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/advancedLogisticSigma/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/advanced-logistic-sigma.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/advancedLogisticTau/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/advanced-logistic-tau.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/affectiveBiasingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/affective-biasing-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/amplifyingEvacuationOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/amplifying-evacuation-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/amplifyingFeelingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/amplifying-feeling-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/amplifyingIntentionOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/amplifying-intention-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/bodyEta/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/body-eta.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/inhibitingFeelingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/inhibiting-feeling-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/inhibitingIntentionOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/inhibiting-intention-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/inhibitingWalkRandOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/inhibiting-walk-rand-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/logisticSigma/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/logistic-sigma.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/logisticTau/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/logistic-tau.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/mentalEta/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/mental-eta.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/persistingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/persisting-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/CognitiveSpec/sensingOmega/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-cognitive-spec/sensing-omega.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireEvacuate///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-evacuate/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireEvacuate/DesireEvacuate/#kotlin.Double#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-evacuate/-desire-evacuate.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireEvacuate/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-evacuate/combination-function.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireWalkRandomly///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-walk-randomly/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireWalkRandomly/DesireWalkRandomly/#kotlin.Double#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-walk-randomly/-desire-walk-randomly.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/DesireWalkRandomly/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-desire-walk-randomly/combination-function.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/Fear///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-fear/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/Fear/Fear/#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.collections.List[it.unibo.alchemist.model.cognitive.CognitiveModel]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-fear/-fear.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/Fear/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-fear/combination-function.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionEvacuate///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-evacuate/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionEvacuate/IntentionEvacuate/#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-evacuate/-intention-evacuate.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionEvacuate/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-evacuate/combination-function.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionWalkRandomly///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-walk-randomly/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionWalkRandomly/IntentionWalkRandomly/#kotlin.Function0[kotlin.Double]#kotlin.Function0[kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-walk-randomly/-intention-walk-randomly.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/IntentionWalkRandomly/combinationFunction/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-intention-walk-randomly/combination-function.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/MentalCognitiveCharacteristic///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-mental-cognitive-characteristic/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/MentalCognitiveCharacteristic/MentalCognitiveCharacteristic/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-mental-cognitive-characteristic/-mental-cognitive-characteristic.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.cognitive/MentalCognitiveCharacteristic/update/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.cognitive/-mental-cognitive-characteristic/update.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.ADULT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-a-d-u-l-t/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.CHILD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-c-h-i-l-d/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion/ADULT_THRESHOLD/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/-a-d-u-l-t_-t-h-r-e-s-h-o-l-d.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion/CHILD_THRESHOLD/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/-c-h-i-l-d_-t-h-r-e-s-h-o-l-d.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion/fromAny/#kotlin.Any/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/from-any.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion/fromString/#kotlin.String/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/from-string.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.Companion/fromYears/#kotlin.Int/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-companion/from-years.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age.ELDERLY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/-e-l-d-e-r-l-y/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age/entries/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/entries.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age/valueOf/#kotlin.String/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/value-of.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Age/values/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-age/values.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Characteristic///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-characteristic/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Compliance///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Compliance/Compliance/#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance/-compliance.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Compliance/level/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance/level.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/adult-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/adult-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/child-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/child-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/elderly-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/ComplianceSpec/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-compliance-spec/elderly-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/-companion/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender.Companion/fromString/#kotlin.String/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/-companion/from-string.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender.FEMALE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/-f-e-m-a-l-e/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender.MALE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/-m-a-l-e/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender/entries/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/entries.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender/valueOf/#kotlin.String/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/value-of.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Gender/values/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-gender/values.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitude///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitude/HelpAttitude/#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude/-help-attitude.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitude/level/#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender#kotlin.Boolean/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude/level.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/adult-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/adult-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/child-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/child-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/elderly-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultFemale/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-female/elderly-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/adult-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/adult-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/child-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/child-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/elderly-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.AdultMale/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-adult-male/elderly-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/adult-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/adult-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/child-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/child-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/elderly-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyFemale/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-female/elderly-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/adult-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/adult-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/child-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/child-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/elderly-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec.ElderlyMale/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/-elderly-male/elderly-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/HelpAttitudeSpec///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-help-attitude-spec/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/-companion/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed.Companion/default/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/-companion/default.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed/Speed/#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender#org.apache.commons.math3.random.RandomGenerator/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/-speed.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed/running/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/running.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/Speed/walking/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed/walking.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/adultFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/adult-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/adultMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/adult-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/childFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/child-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/childMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/child-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/default/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/default.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/elderlyFemale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/elderly-female.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/elderlyMale/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/elderly-male.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact.individual/SpeedSpec/variance/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact.individual/-speed-spec/variance.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact//PARAMETERS_FILE/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-p-a-r-a-m-e-t-e-r-s_-f-i-l-e.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/ImpactModel/#kotlin.Double#kotlin.Function0[kotlin.collections.List[it.unibo.alchemist.model.cognitive.CognitiveModel]]#kotlin.Function0[kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/-impact-model.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/dangerBelief/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/danger-belief.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/escapeIntention/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/escape-intention.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/fear/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/fear.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/remainIntention/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/remain-intention.html +$dokka.location:it.unibo.alchemist.model.cognitive.impact/ImpactModel/update/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.impact/-impact-model/update.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/DynamicallyPursue///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-dynamically-pursue/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/DynamicallyPursue/DynamicallyPursue/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-dynamically-pursue/-dynamically-pursue.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/DynamicallyPursue/setDestination/#it.unibo.alchemist.model.positions.Euclidean2DPosition#kotlin.Boolean/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-dynamically-pursue/set-destination.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/-companion/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore.Companion/DEFAULT_IMPASSE_WEIGHT/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/-companion/-d-e-f-a-u-l-t_-i-m-p-a-s-s-e_-w-e-i-g-h-t.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore/Explore/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/-explore.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore/action/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/action.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Explore/inNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-explore/in-new-room.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/FollowRoute///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-follow-route/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/FollowRoute/FollowRoute/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-follow-route/-follow-route.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/FollowRoute/inNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-follow-route/in-new-room.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/FollowRoute/inUnexpectedNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon#it.unibo.alchemist.model.geometry.ConvexPolygon#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-follow-route/in-unexpected-new-room.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/GoalOrientedExploration///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-goal-oriented-exploration/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/GoalOrientedExploration/GoalOrientedExploration/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-goal-oriented-exploration/-goal-oriented-exploration.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/GoalOrientedExploration/inNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-goal-oriented-exploration/in-new-room.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Pursue///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-pursue/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Pursue/Pursue/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-pursue/-pursue.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/Pursue/inNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-pursue/in-new-room.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/ReachDestination///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-reach-destination/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/ReachDestination/ReachDestination/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-reach-destination/-reach-destination.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/ReachDestination/inNewRoom/#it.unibo.alchemist.model.geometry.ConvexPolygon/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-reach-destination/in-new-room.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/ReachKnownDestination///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-reach-known-destination/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.navigation/ReachKnownDestination/ReachKnownDestination/#it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation]]),TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.geometry.ConvexPolygon,it.unibo.alchemist.model.geometry.navigationgraph.Euclidean2DPassage]#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.navigation/-reach-known-destination/-reach-known-destination.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/Cognitive/#it.unibo.alchemist.model.physics.PhysicsEnvironment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]])]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.GeometricShapeFactory[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Molecule?/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/-cognitive.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/cognitiveModel/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/cognitive-model.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/danger/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/danger.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive/to-string.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive2-d/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Cognitive2D/Cognitive2D/#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Molecule?/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive2-d/-cognitive2-d.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/CognitivePedestrian///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive-pedestrian/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/CognitivePedestrian/CognitivePedestrian/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive-pedestrian/-cognitive-pedestrian.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/CognitivePedestrian/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-cognitive-pedestrian/speed.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/HeterogeneousPedestrian///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-heterogeneous-pedestrian/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/HeterogeneousPedestrian/HeterogeneousPedestrian/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-heterogeneous-pedestrian/-heterogeneous-pedestrian.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/HeterogeneousPedestrian/runningSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-heterogeneous-pedestrian/running-speed.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/HeterogeneousPedestrian/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-heterogeneous-pedestrian/to-string.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/HeterogeneousPedestrian/walkingSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-heterogeneous-pedestrian/walking-speed.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/Human/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender#it.unibo.alchemist.model.cognitive.impact.individual.Speed#kotlin.Double#it.unibo.alchemist.model.cognitive.impact.individual.HelpAttitude/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/-human.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/Human/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Any#kotlin.String#it.unibo.alchemist.model.cognitive.impact.individual.Speed#kotlin.Double#it.unibo.alchemist.model.cognitive.impact.individual.HelpAttitude/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/-human.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/age/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/age.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/compliance/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/compliance.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/gender/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/gender.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/helpAttitude/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/help-attitude.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/speed.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Human/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-human/to-string.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/-companion/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting.Companion/pathExists/org.jgrapht.Graph[TypeParam(bounds=[kotlin.Any?]),*]#TypeParam(bounds=[kotlin.Any?])#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/-companion/path-exists.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/Orienting/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.environments.EnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]])]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]]),org.jgrapht.graph.DefaultEdge]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/-orienting.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/cognitiveMap/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/cognitive-map.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/createLandmarkIn/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/create-landmark-in.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/environment.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/knowledgeDegree/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/knowledge-degree.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/randomGenerator/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/random-generator.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/to-string.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting/volatileMemory/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting/volatile-memory.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/Orienting2D/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon]),org.jgrapht.graph.DefaultEdge]#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/-orienting2-d.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/createLandmarkIn/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/create-landmark-in.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/environment.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/knowledgeDegree/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/knowledge-degree.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Orienting2D/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-orienting2-d/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/Pedestrian/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/-pedestrian.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/runningSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/running-speed.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/speed.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/to-string.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Pedestrian/walkingSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-pedestrian/walking-speed.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive/Perceptive/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.physics.InfluenceSphere[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive/-perceptive.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive/fieldOfView/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive/field-of-view.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/-companion/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D.Companion/DEFAULT_FIELD_OF_VIEW_APERTURE/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/-companion/-d-e-f-a-u-l-t_-f-i-e-l-d_-o-f_-v-i-e-w_-a-p-e-r-t-u-r-e.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D.Companion/DEFAULT_FIELD_OF_VIEW_DEPTH/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/-companion/-d-e-f-a-u-l-t_-f-i-e-l-d_-o-f_-v-i-e-w_-d-e-p-t-h.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D/Perceptive2D/#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.physics.InfluenceSphere2D[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/-perceptive2-d.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/environment.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D/fieldOfView/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/field-of-view.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Perceptive2D/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-perceptive2-d/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/PhysicalPedestrian2D/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/-physical-pedestrian2-d.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/avoid/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/avoid.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/avoidanceForces/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/avoidance-forces.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/checkAndPossiblyFall/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/check-and-possibly-fall.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/comfortArea/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/comfort-area.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/comfortRay/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/comfort-ray.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/environment.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/fallenAgentAvoidanceForces/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/fallen-agent-avoidance-forces.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/isFallen/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/is-fallen.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/onFall/#kotlin.Function1[it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])],kotlin.Unit]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/on-fall.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/physicalForces/#it.unibo.alchemist.model.physics.PhysicsEnvironment[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,it.unibo.alchemist.model.geometry.Euclidean2DShapeFactory]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/physical-forces.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/rectangleOfInfluence/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/rectangle-of-influence.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/repulse/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/repulse.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/repulsionForces/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/repulsion-forces.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/shouldFall/#kotlin.collections.List[it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/should-fall.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/PhysicalPedestrian2D/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-physical-pedestrian2-d/to-string.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/RunningPedestrian///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-running-pedestrian/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/RunningPedestrian/RunningPedestrian/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-running-pedestrian/-running-pedestrian.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/RunningPedestrian/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-running-pedestrian/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/RunningPedestrian/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-running-pedestrian/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/RunningPedestrian/runningSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-running-pedestrian/running-speed.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social/Social/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.Group[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/-social.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social/group/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/group.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/Social/toString/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-social/to-string.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/WalkingPedestrian///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-walking-pedestrian/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/WalkingPedestrian/WalkingPedestrian/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-walking-pedestrian/-walking-pedestrian.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/WalkingPedestrian/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-walking-pedestrian/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/WalkingPedestrian/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-walking-pedestrian/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.properties/WalkingPedestrian/walkingSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.properties/-walking-pedestrian/walking-speed.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/BlendedSteering///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-blended-steering/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/BlendedSteering/BlendedSteering/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-blended-steering/-blended-steering.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/CognitiveBehavior///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-cognitive-behavior/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/CognitiveBehavior/CognitiveBehavior/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-cognitive-behavior/-cognitive-behavior.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/CognitiveBehavior/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-cognitive-behavior/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/NavigationPrioritizedSteering///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-navigation-prioritized-steering/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/NavigationPrioritizedSteering/NavigationPrioritizedSteering/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon]),*]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-navigation-prioritized-steering/-navigation-prioritized-steering.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/NavigationPrioritizedSteeringWithPhysics///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-navigation-prioritized-steering-with-physics/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/NavigationPrioritizedSteeringWithPhysics/NavigationPrioritizedSteeringWithPhysics/#it.unibo.alchemist.model.physics.environments.EuclideanPhysics2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon]),*]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-navigation-prioritized-steering-with-physics/-navigation-prioritized-steering-with-physics.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/NavigationPrioritizedSteeringWithPhysics/steerStrategy/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-navigation-prioritized-steering-with-physics/steer-strategy.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PhysicalBlendedSteering///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-physical-blended-steering/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PhysicalBlendedSteering/PhysicalBlendedSteering/#it.unibo.alchemist.model.physics.environments.Dynamics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-physical-blended-steering/-physical-blended-steering.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PhysicalBlendedSteering/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-physical-blended-steering/environment.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PhysicalBlendedSteering/execute/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-physical-blended-steering/execute.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PhysicalBlendedSteering/steerStrategy/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-physical-blended-steering/steer-strategy.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PrioritySteering///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-priority-steering/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/PrioritySteering/PrioritySteering/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-priority-steering/-priority-steering.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior/SteeringBehavior/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]#it.unibo.alchemist.model.cognitive.PedestrianProperty[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.TimeDistribution[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.SteeringStrategy[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/-steering-behavior.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior/execute/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/execute.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior/steerActions/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/steer-actions.html +$dokka.location:it.unibo.alchemist.model.cognitive.reactions/SteeringBehavior/steerStrategy/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.reactions/-steering-behavior/steer-strategy.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/DistanceWeighted///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-distance-weighted/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/DistanceWeighted/DistanceWeighted/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-distance-weighted/-distance-weighted.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Filtered///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-filtered/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Filtered/Filtered/#it.unibo.alchemist.model.cognitive.SteeringStrategy[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]#kotlin.Function1[kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]],kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-filtered/-filtered.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Filtered/computeNextPosition/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-filtered/compute-next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Nearest///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-nearest/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Nearest/Nearest/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-nearest/-nearest.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent.Companion///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-companion/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent.Companion/DEFAULT_ALPHA/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-companion/-d-e-f-a-u-l-t_-a-l-p-h-a.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent.Companion/DEFAULT_DELTA/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-companion/-d-e-f-a-u-l-t_-d-e-l-t-a.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent.Companion/DEFAULT_MAX_WALK_RATIO/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-companion/-d-e-f-a-u-l-t_-m-a-x_-w-a-l-k_-r-a-t-i-o.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent.Companion/DEFAULT_TOLERANCE_ANGLE/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-companion/-d-e-f-a-u-l-t_-t-o-l-e-r-a-n-c-e_-a-n-g-l-e.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent/SinglePrevalent/#it.unibo.alchemist.model.environments.Euclidean2DEnvironmentWithGraph[*,TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon]),*]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Function1[kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]],it.unibo.alchemist.model.cognitive.NavigationAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition,it.unibo.alchemist.model.geometry.Euclidean2DTransformation,*,*,TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexPolygon]),*]]#kotlin.Double#kotlin.Double#kotlin.Function0[kotlin.Double]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/-single-prevalent.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/SinglePrevalent/computeNextPosition/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-single-prevalent/compute-next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Sum///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-sum/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Sum/Sum/#it.unibo.alchemist.model.physics.environments.Physics2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.cognitive.SteeringStrategy[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-sum/-sum.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Sum/computeNextPosition/#it.unibo.alchemist.model.positions.Euclidean2DPosition/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-sum/compute-next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Sum/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-sum/node.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Sum/nonPhysicalStrategy/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-sum/non-physical-strategy.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/TypeBased///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-type-based/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/TypeBased/TypeBased/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#java.util.LinkedHashMap[kotlin.reflect.KClass[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]],kotlin.Double]#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-type-based/-type-based.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Weighted///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-weighted/index.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Weighted/Weighted/#it.unibo.alchemist.model.environments.Euclidean2DEnvironment[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Function1[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition],kotlin.Double]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-weighted/-weighted.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Weighted/computeNextPosition/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-weighted/compute-next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive.steering/Weighted/computeTarget/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),it.unibo.alchemist.model.positions.Euclidean2DPosition]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive.steering/-weighted/compute-target.html +$dokka.location:it.unibo.alchemist.model.cognitive////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/dangerBelief/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/danger-belief.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/escapeIntention/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/escape-intention.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/fear/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/fear.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/remainIntention/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/remain-intention.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/update/#kotlin.Double/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/update.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveModel/wantsToEscape/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-model/wants-to-escape.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-property/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveProperty/cognitiveModel/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-property/cognitive-model.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveProperty/danger/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-property/danger.html +$dokka.location:it.unibo.alchemist.model.cognitive/CognitiveProperty/influentialPeople/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-cognitive-property/influential-people.html +$dokka.location:it.unibo.alchemist.model.cognitive/Group///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/Group/members/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group/members.html +$dokka.location:it.unibo.alchemist.model.cognitive/GroupSteeringAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group-steering-action/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/GroupSteeringAction/group/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group-steering-action/group.html +$dokka.location:it.unibo.alchemist.model.cognitive/GroupWithLeader///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group-with-leader/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/GroupWithLeader/leader/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-group-with-leader/leader.html +$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/HeterogeneousPedestrianModel/#it.unibo.alchemist.model.cognitive.impact.individual.Age#it.unibo.alchemist.model.cognitive.impact.individual.Gender#it.unibo.alchemist.model.cognitive.impact.individual.Speed#kotlin.Double#it.unibo.alchemist.model.cognitive.impact.individual.HelpAttitude/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/-heterogeneous-pedestrian-model.html +$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/age/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/age.html +$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/compliance/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/compliance.html +$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/gender/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/gender.html +$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/helpAttitude/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/help-attitude.html +$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/probabilityOfHelping/#it.unibo.alchemist.model.cognitive.HeterogeneousPedestrianModel[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^^]])]])]#kotlin.Boolean/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/probability-of-helping.html +$dokka.location:it.unibo.alchemist.model.cognitive/HeterogeneousPedestrianModel/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-heterogeneous-pedestrian-model/speed.html +$dokka.location:it.unibo.alchemist.model.cognitive/Human2DProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human2-d-property/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/age/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/age.html +$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/compliance/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/compliance.html +$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/gender/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/gender.html +$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/helpAttitude/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/help-attitude.html +$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/probabilityOfHelping/#it.unibo.alchemist.model.cognitive.HeterogeneousPedestrianModel[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^^]])]])]#kotlin.Boolean/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/probability-of-helping.html +$dokka.location:it.unibo.alchemist.model.cognitive/HumanProperty/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-human-property/speed.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/crossDoor/#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/cross-door.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/currentRoom/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/current-room.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/doorsInSight/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/doors-in-sight.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/environment.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/moveToFinal/#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/move-to-final.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/navigatingNode/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/navigating-node.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/orientingProperty/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/orienting-property.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/pedestrianPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/pedestrian-position.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationAction/stop/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-action/stop.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy/action/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy/action.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy/inNewRoom/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy/in-new-room.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy/inUnexpectedNewRoom/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy/in-unexpected-new-room.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy/orientingCapability/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy/orienting-capability.html +$dokka.location:it.unibo.alchemist.model.cognitive/NavigationStrategy2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-navigation-strategy2-d/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent/cognitiveMap/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent/cognitive-map.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent/knowledgeDegree/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent/knowledge-degree.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent/registerVisit/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent/register-visit.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent/volatileMemory/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent/volatile-memory.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingAgent2D///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-agent2-d/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/cognitiveMap/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/cognitive-map.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/createLandmarkIn/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/create-landmark-in.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/environment/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/environment.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/knowledgeDegree/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/knowledge-degree.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/registerVisit/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.ConvexShape[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^^], it.unibo.alchemist.model.geometry.Vector[^^^]])]])]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/register-visit.html +$dokka.location:it.unibo.alchemist.model.cognitive/OrientingProperty/volatileMemory/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-orienting-property/volatile-memory.html +$dokka.location:it.unibo.alchemist.model.cognitive/PedestrianProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-pedestrian-property/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/PedestrianProperty/speed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-pedestrian-property/speed.html +$dokka.location:it.unibo.alchemist.model.cognitive/PerceptiveProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-perceptive-property/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/PerceptiveProperty/fieldOfView/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-perceptive-property/field-of-view.html +$dokka.location:it.unibo.alchemist.model.cognitive/PerceptiveProperty/senses/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-perceptive-property/senses.html +$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy/computeNextPosition/#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/compute-next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy/computeNextPosition/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/compute-next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy/computeTarget/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/compute-target.html +$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy/node/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/node.html +$dokka.location:it.unibo.alchemist.model.cognitive/PhysicalSteeringStrategy/nonPhysicalStrategy/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-physical-steering-strategy/non-physical-strategy.html +$dokka.location:it.unibo.alchemist.model.cognitive/RunningPedestrianProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-running-pedestrian-property/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/RunningPedestrianProperty/runningSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-running-pedestrian-property/running-speed.html +$dokka.location:it.unibo.alchemist.model.cognitive/SocialProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-social-property/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/SocialProperty/group/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-social-property/group.html +$dokka.location:it.unibo.alchemist.model.cognitive/SteeringAction///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-action/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/SteeringAction/nextPosition/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-action/next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive/SteeringActionWithTarget///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-action-with-target/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/SteeringActionWithTarget/target/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-action-with-target/target.html +$dokka.location:it.unibo.alchemist.model.cognitive/SteeringActionWithTarget/targetDistanceTo/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-action-with-target/target-distance-to.html +$dokka.location:it.unibo.alchemist.model.cognitive/SteeringStrategy///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-strategy/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/SteeringStrategy/computeNextPosition/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-strategy/compute-next-position.html +$dokka.location:it.unibo.alchemist.model.cognitive/SteeringStrategy/computeTarget/#kotlin.collections.List[it.unibo.alchemist.model.cognitive.SteeringAction[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-steering-strategy/compute-target.html +$dokka.location:it.unibo.alchemist.model.cognitive/WalkingPedestrianProperty///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-walking-pedestrian-property/index.html +$dokka.location:it.unibo.alchemist.model.cognitive/WalkingPedestrianProperty/walkingSpeed/#/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.model.cognitive/-walking-pedestrian-property/walking-speed.html +$dokka.location:it.unibo.alchemist.util////PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/index.html +$dokka.location:it.unibo.alchemist.util//lazyMutable/#kotlin.Function0[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/lazy-mutable.html +$dokka.location:it.unibo.alchemist.util/LazyMutable///PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/-lazy-mutable/index.html +$dokka.location:it.unibo.alchemist.util/LazyMutable/LazyMutable/#kotlin.Function0[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/-lazy-mutable/-lazy-mutable.html +$dokka.location:it.unibo.alchemist.util/LazyMutable/getValue/#kotlin.Any?#kotlin.reflect.KProperty[*]/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/-lazy-mutable/get-value.html +$dokka.location:it.unibo.alchemist.util/LazyMutable/setValue/#kotlin.Any?#kotlin.reflect.KProperty[*]#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-cognitive-agents/it.unibo.alchemist.util/-lazy-mutable/set-value.html +it.unibo.alchemist.model.cognitive +it.unibo.alchemist.model.cognitive.actions +it.unibo.alchemist.model.cognitive.conditions +it.unibo.alchemist.model.cognitive.environments +it.unibo.alchemist.model.cognitive.groups +it.unibo.alchemist.model.cognitive.impact +it.unibo.alchemist.model.cognitive.impact.cognitive +it.unibo.alchemist.model.cognitive.impact.individual +it.unibo.alchemist.model.cognitive.navigation +it.unibo.alchemist.model.cognitive.properties +it.unibo.alchemist.model.cognitive.reactions +it.unibo.alchemist.model.cognitive.steering +it.unibo.alchemist.util diff --git a/dokka-cache/org.jooq/jool/0.9.15.list b/dokka-cache/org.jooq/jool/0.9.15.list deleted file mode 100644 index c072111699..0000000000 --- a/dokka-cache/org.jooq/jool/0.9.15.list +++ /dev/null @@ -1,9 +0,0 @@ -module:org.jooq.jool -org.jooq.lambda -org.jooq.lambda.exception -org.jooq.lambda.fi.lang -org.jooq.lambda.fi.util -org.jooq.lambda.fi.util.concurrent -org.jooq.lambda.fi.util.function -org.jooq.lambda.function -org.jooq.lambda.tuple From 11ad0c2bb98d5dbaed8e3383b14b29a8481bab13 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 13:44:09 +0000 Subject: [PATCH 066/196] chore(build): update the javadoc.io cache --- dokka-cache/org.danilopianini/conrec/0.1.1.list | 1 - dokka-cache/org.jooq/jool/0.9.15.list | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) delete mode 100644 dokka-cache/org.danilopianini/conrec/0.1.1.list create mode 100644 dokka-cache/org.jooq/jool/0.9.15.list diff --git a/dokka-cache/org.danilopianini/conrec/0.1.1.list b/dokka-cache/org.danilopianini/conrec/0.1.1.list deleted file mode 100644 index 55d3475f3d..0000000000 --- a/dokka-cache/org.danilopianini/conrec/0.1.1.list +++ /dev/null @@ -1 +0,0 @@ -conrec diff --git a/dokka-cache/org.jooq/jool/0.9.15.list b/dokka-cache/org.jooq/jool/0.9.15.list new file mode 100644 index 0000000000..c072111699 --- /dev/null +++ b/dokka-cache/org.jooq/jool/0.9.15.list @@ -0,0 +1,9 @@ +module:org.jooq.jool +org.jooq.lambda +org.jooq.lambda.exception +org.jooq.lambda.fi.lang +org.jooq.lambda.fi.util +org.jooq.lambda.fi.util.concurrent +org.jooq.lambda.fi.util.function +org.jooq.lambda.function +org.jooq.lambda.tuple From 4b4f9f3687d915b0e4f8f85d262eff99f7981619 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 14:00:18 +0000 Subject: [PATCH 067/196] chore(build): update the javadoc.io cache --- dokka-cache/com.javadocmd/simplelatlng/1.4.0.list | 3 --- dokka-cache/org.danilopianini/conrec/0.1.1.list | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 dokka-cache/com.javadocmd/simplelatlng/1.4.0.list create mode 100644 dokka-cache/org.danilopianini/conrec/0.1.1.list diff --git a/dokka-cache/com.javadocmd/simplelatlng/1.4.0.list b/dokka-cache/com.javadocmd/simplelatlng/1.4.0.list deleted file mode 100644 index bcd404eb01..0000000000 --- a/dokka-cache/com.javadocmd/simplelatlng/1.4.0.list +++ /dev/null @@ -1,3 +0,0 @@ -com.javadocmd.simplelatlng -com.javadocmd.simplelatlng.util -com.javadocmd.simplelatlng.window diff --git a/dokka-cache/org.danilopianini/conrec/0.1.1.list b/dokka-cache/org.danilopianini/conrec/0.1.1.list new file mode 100644 index 0000000000..55d3475f3d --- /dev/null +++ b/dokka-cache/org.danilopianini/conrec/0.1.1.list @@ -0,0 +1 @@ +conrec From 4998e630a347649a2115afc6dd4f2fad10c4a36e Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 14:18:27 +0000 Subject: [PATCH 068/196] chore(build): update the javadoc.io cache --- dokka-cache/com.javadocmd/simplelatlng/1.4.0.list | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 dokka-cache/com.javadocmd/simplelatlng/1.4.0.list diff --git a/dokka-cache/com.javadocmd/simplelatlng/1.4.0.list b/dokka-cache/com.javadocmd/simplelatlng/1.4.0.list new file mode 100644 index 0000000000..bcd404eb01 --- /dev/null +++ b/dokka-cache/com.javadocmd/simplelatlng/1.4.0.list @@ -0,0 +1,3 @@ +com.javadocmd.simplelatlng +com.javadocmd.simplelatlng.util +com.javadocmd.simplelatlng.window From eab6d0f5ef9012eab60d719dc8b0738b7d3c8640 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 14:39:14 +0000 Subject: [PATCH 069/196] chore(build): update the javadoc.io cache --- dokka-cache/com.miglayout/miglayout-swing/11.4.2.list | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 dokka-cache/com.miglayout/miglayout-swing/11.4.2.list diff --git a/dokka-cache/com.miglayout/miglayout-swing/11.4.2.list b/dokka-cache/com.miglayout/miglayout-swing/11.4.2.list deleted file mode 100644 index c1ff13fe3d..0000000000 --- a/dokka-cache/com.miglayout/miglayout-swing/11.4.2.list +++ /dev/null @@ -1,2 +0,0 @@ -module:com.miglayout.swing -net.miginfocom.swing From 49a2e124b9ea1291cacb109c89e4d162d7eca81a Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 14:53:36 +0000 Subject: [PATCH 070/196] chore(build): update the javadoc.io cache --- dokka-cache/com.miglayout/miglayout-swing/11.4.2.list | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 dokka-cache/com.miglayout/miglayout-swing/11.4.2.list diff --git a/dokka-cache/com.miglayout/miglayout-swing/11.4.2.list b/dokka-cache/com.miglayout/miglayout-swing/11.4.2.list new file mode 100644 index 0000000000..c1ff13fe3d --- /dev/null +++ b/dokka-cache/com.miglayout/miglayout-swing/11.4.2.list @@ -0,0 +1,2 @@ +module:com.miglayout.swing +net.miginfocom.swing From 4d40681958abc5308658d47b3c5426238d214434 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 15:15:15 +0000 Subject: [PATCH 071/196] chore(build): update the javadoc.io cache --- dokka-cache/com.uchuhimo/konf-js/1.1.2.list | 19 ------------------ .../3.3.3.list | 20 ------------------- 2 files changed, 39 deletions(-) delete mode 100644 dokka-cache/com.uchuhimo/konf-js/1.1.2.list delete mode 100644 dokka-cache/io.ktor/ktor-client-content-negotiation/3.3.3.list diff --git a/dokka-cache/com.uchuhimo/konf-js/1.1.2.list b/dokka-cache/com.uchuhimo/konf-js/1.1.2.list deleted file mode 100644 index 1dcf10fda1..0000000000 --- a/dokka-cache/com.uchuhimo/konf-js/1.1.2.list +++ /dev/null @@ -1,19 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:com.uchuhimo.konf.source.js////PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/index.html -$dokka.location:com.uchuhimo.konf.source.js//toJs/com.uchuhimo.konf.Config#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/to-js.html -$dokka.location:com.uchuhimo.konf.source.js/JsProvider///PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/index.html -$dokka.location:com.uchuhimo.konf.source.js/JsProvider/get/#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/get.html -$dokka.location:com.uchuhimo.konf.source.js/JsProvider/inputStream/#java.io.InputStream/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/input-stream.html -$dokka.location:com.uchuhimo.konf.source.js/JsProvider/reader/#java.io.Reader/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/reader.html -$dokka.location:com.uchuhimo.konf.source.js/JsWriter///PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/index.html -$dokka.location:com.uchuhimo.konf.source.js/JsWriter/JsWriter/#com.uchuhimo.konf.Config/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/-js-writer.html -$dokka.location:com.uchuhimo.konf.source.js/JsWriter/config/#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/config.html -$dokka.location:com.uchuhimo.konf.source.js/JsWriter/toOutputStream/#java.io.OutputStream/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/to-output-stream.html -$dokka.location:com.uchuhimo.konf.source.js/JsWriter/toWriter/#java.io.Writer/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/to-writer.html -$dokka.location:com.uchuhimo.konf.source////PointingToDeclaration/konf-js/com.uchuhimo.konf.source/index.html -$dokka.location:com.uchuhimo.konf.source//js/com.uchuhimo.konf.source.DefaultLoaders#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source/js.html -$dokka.location:com.uchuhimo.konf.source//js/com.uchuhimo.konf.source.DefaultProviders#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source/js.html -com.uchuhimo.konf.source -com.uchuhimo.konf.source.js - diff --git a/dokka-cache/io.ktor/ktor-client-content-negotiation/3.3.3.list b/dokka-cache/io.ktor/ktor-client-content-negotiation/3.3.3.list deleted file mode 100644 index be65947603..0000000000 --- a/dokka-cache/io.ktor/ktor-client-content-negotiation/3.3.3.list +++ /dev/null @@ -1,20 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:io.ktor.client.plugins.contentnegotiation////PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/index.html -$dokka.location:io.ktor.client.plugins.contentnegotiation//ContentNegotiation/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation.html -$dokka.location:io.ktor.client.plugins.contentnegotiation//exclude/io.ktor.client.request.HttpRequestBuilder#io.ktor.http.ContentType/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/exclude.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentConverterException///PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-converter-exception/index.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentConverterException/ContentConverterException/#kotlin.String/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-converter-exception/-content-converter-exception.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig///PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/index.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/ContentNegotiationConfig/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/-content-negotiation-config.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/clearIgnoredTypes/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/clear-ignored-types.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/defaultAcceptHeaderQValue/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/default-accept-header-q-value.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/ignoreType/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/ignore-type.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/ignoreType/#kotlin.reflect.KClass[*]/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/ignore-type.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/register/#io.ktor.http.ContentType#TypeParam(bounds=[io.ktor.serialization.ContentConverter])#io.ktor.http.ContentTypeMatcher#kotlin.Function1[TypeParam(bounds=[io.ktor.serialization.ContentConverter]),kotlin.Unit]/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/register.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/register/#io.ktor.http.ContentType#TypeParam(bounds=[io.ktor.serialization.ContentConverter])#kotlin.Function1[TypeParam(bounds=[io.ktor.serialization.ContentConverter]),kotlin.Unit]/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/register.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/removeIgnoredType/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/remove-ignored-type.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/removeIgnoredType/#kotlin.reflect.KClass[*]/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/remove-ignored-type.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/JsonContentTypeMatcher///PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-json-content-type-matcher/index.html -$dokka.location:io.ktor.client.plugins.contentnegotiation/JsonContentTypeMatcher/contains/#io.ktor.http.ContentType/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-json-content-type-matcher/contains.html -io.ktor.client.plugins.contentnegotiation From 49c7b451f4fa285548632f08e200967b7e8fea41 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 15:30:53 +0000 Subject: [PATCH 072/196] chore(build): update the javadoc.io cache --- dokka-cache/com.uchuhimo/konf-js/1.1.2.list | 19 ++++++++++++++++++ .../3.3.3.list | 20 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 dokka-cache/com.uchuhimo/konf-js/1.1.2.list create mode 100644 dokka-cache/io.ktor/ktor-client-content-negotiation/3.3.3.list diff --git a/dokka-cache/com.uchuhimo/konf-js/1.1.2.list b/dokka-cache/com.uchuhimo/konf-js/1.1.2.list new file mode 100644 index 0000000000..1dcf10fda1 --- /dev/null +++ b/dokka-cache/com.uchuhimo/konf-js/1.1.2.list @@ -0,0 +1,19 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:com.uchuhimo.konf.source.js////PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/index.html +$dokka.location:com.uchuhimo.konf.source.js//toJs/com.uchuhimo.konf.Config#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/to-js.html +$dokka.location:com.uchuhimo.konf.source.js/JsProvider///PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/index.html +$dokka.location:com.uchuhimo.konf.source.js/JsProvider/get/#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/get.html +$dokka.location:com.uchuhimo.konf.source.js/JsProvider/inputStream/#java.io.InputStream/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/input-stream.html +$dokka.location:com.uchuhimo.konf.source.js/JsProvider/reader/#java.io.Reader/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/reader.html +$dokka.location:com.uchuhimo.konf.source.js/JsWriter///PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/index.html +$dokka.location:com.uchuhimo.konf.source.js/JsWriter/JsWriter/#com.uchuhimo.konf.Config/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/-js-writer.html +$dokka.location:com.uchuhimo.konf.source.js/JsWriter/config/#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/config.html +$dokka.location:com.uchuhimo.konf.source.js/JsWriter/toOutputStream/#java.io.OutputStream/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/to-output-stream.html +$dokka.location:com.uchuhimo.konf.source.js/JsWriter/toWriter/#java.io.Writer/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/to-writer.html +$dokka.location:com.uchuhimo.konf.source////PointingToDeclaration/konf-js/com.uchuhimo.konf.source/index.html +$dokka.location:com.uchuhimo.konf.source//js/com.uchuhimo.konf.source.DefaultLoaders#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source/js.html +$dokka.location:com.uchuhimo.konf.source//js/com.uchuhimo.konf.source.DefaultProviders#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source/js.html +com.uchuhimo.konf.source +com.uchuhimo.konf.source.js + diff --git a/dokka-cache/io.ktor/ktor-client-content-negotiation/3.3.3.list b/dokka-cache/io.ktor/ktor-client-content-negotiation/3.3.3.list new file mode 100644 index 0000000000..be65947603 --- /dev/null +++ b/dokka-cache/io.ktor/ktor-client-content-negotiation/3.3.3.list @@ -0,0 +1,20 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:io.ktor.client.plugins.contentnegotiation////PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/index.html +$dokka.location:io.ktor.client.plugins.contentnegotiation//ContentNegotiation/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation.html +$dokka.location:io.ktor.client.plugins.contentnegotiation//exclude/io.ktor.client.request.HttpRequestBuilder#io.ktor.http.ContentType/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/exclude.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentConverterException///PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-converter-exception/index.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentConverterException/ContentConverterException/#kotlin.String/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-converter-exception/-content-converter-exception.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig///PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/index.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/ContentNegotiationConfig/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/-content-negotiation-config.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/clearIgnoredTypes/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/clear-ignored-types.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/defaultAcceptHeaderQValue/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/default-accept-header-q-value.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/ignoreType/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/ignore-type.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/ignoreType/#kotlin.reflect.KClass[*]/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/ignore-type.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/register/#io.ktor.http.ContentType#TypeParam(bounds=[io.ktor.serialization.ContentConverter])#io.ktor.http.ContentTypeMatcher#kotlin.Function1[TypeParam(bounds=[io.ktor.serialization.ContentConverter]),kotlin.Unit]/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/register.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/register/#io.ktor.http.ContentType#TypeParam(bounds=[io.ktor.serialization.ContentConverter])#kotlin.Function1[TypeParam(bounds=[io.ktor.serialization.ContentConverter]),kotlin.Unit]/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/register.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/removeIgnoredType/#/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/remove-ignored-type.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/ContentNegotiationConfig/removeIgnoredType/#kotlin.reflect.KClass[*]/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-content-negotiation-config/remove-ignored-type.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/JsonContentTypeMatcher///PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-json-content-type-matcher/index.html +$dokka.location:io.ktor.client.plugins.contentnegotiation/JsonContentTypeMatcher/contains/#io.ktor.http.ContentType/PointingToDeclaration/ktor-client-content-negotiation/io.ktor.client.plugins.contentnegotiation/-json-content-type-matcher/contains.html +io.ktor.client.plugins.contentnegotiation From bee728db50c923e66a667373af6fb7fa3cdaca68 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 15:46:35 +0000 Subject: [PATCH 073/196] chore(build): update the javadoc.io cache --- dokka-cache/com.uchuhimo/konf-js/1.1.2.list | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 dokka-cache/com.uchuhimo/konf-js/1.1.2.list diff --git a/dokka-cache/com.uchuhimo/konf-js/1.1.2.list b/dokka-cache/com.uchuhimo/konf-js/1.1.2.list deleted file mode 100644 index 1dcf10fda1..0000000000 --- a/dokka-cache/com.uchuhimo/konf-js/1.1.2.list +++ /dev/null @@ -1,19 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:com.uchuhimo.konf.source.js////PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/index.html -$dokka.location:com.uchuhimo.konf.source.js//toJs/com.uchuhimo.konf.Config#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/to-js.html -$dokka.location:com.uchuhimo.konf.source.js/JsProvider///PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/index.html -$dokka.location:com.uchuhimo.konf.source.js/JsProvider/get/#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/get.html -$dokka.location:com.uchuhimo.konf.source.js/JsProvider/inputStream/#java.io.InputStream/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/input-stream.html -$dokka.location:com.uchuhimo.konf.source.js/JsProvider/reader/#java.io.Reader/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/reader.html -$dokka.location:com.uchuhimo.konf.source.js/JsWriter///PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/index.html -$dokka.location:com.uchuhimo.konf.source.js/JsWriter/JsWriter/#com.uchuhimo.konf.Config/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/-js-writer.html -$dokka.location:com.uchuhimo.konf.source.js/JsWriter/config/#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/config.html -$dokka.location:com.uchuhimo.konf.source.js/JsWriter/toOutputStream/#java.io.OutputStream/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/to-output-stream.html -$dokka.location:com.uchuhimo.konf.source.js/JsWriter/toWriter/#java.io.Writer/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/to-writer.html -$dokka.location:com.uchuhimo.konf.source////PointingToDeclaration/konf-js/com.uchuhimo.konf.source/index.html -$dokka.location:com.uchuhimo.konf.source//js/com.uchuhimo.konf.source.DefaultLoaders#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source/js.html -$dokka.location:com.uchuhimo.konf.source//js/com.uchuhimo.konf.source.DefaultProviders#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source/js.html -com.uchuhimo.konf.source -com.uchuhimo.konf.source.js - From ff8ea2dfce78575c563e2f614be2e7a9688e79b2 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 16:05:00 +0000 Subject: [PATCH 074/196] chore(build): update the javadoc.io cache --- dokka-cache/com.uchuhimo/konf-js/1.1.2.list | 19 +++++++++++++++++++ dokka-cache/org.graphstream/gs-algo/2.0.list | 11 ----------- .../mapsforge-map-awt/0.25.0.list | 4 ---- 3 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 dokka-cache/com.uchuhimo/konf-js/1.1.2.list delete mode 100644 dokka-cache/org.graphstream/gs-algo/2.0.list delete mode 100644 dokka-cache/org.mapsforge/mapsforge-map-awt/0.25.0.list diff --git a/dokka-cache/com.uchuhimo/konf-js/1.1.2.list b/dokka-cache/com.uchuhimo/konf-js/1.1.2.list new file mode 100644 index 0000000000..1dcf10fda1 --- /dev/null +++ b/dokka-cache/com.uchuhimo/konf-js/1.1.2.list @@ -0,0 +1,19 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:com.uchuhimo.konf.source.js////PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/index.html +$dokka.location:com.uchuhimo.konf.source.js//toJs/com.uchuhimo.konf.Config#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/to-js.html +$dokka.location:com.uchuhimo.konf.source.js/JsProvider///PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/index.html +$dokka.location:com.uchuhimo.konf.source.js/JsProvider/get/#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/get.html +$dokka.location:com.uchuhimo.konf.source.js/JsProvider/inputStream/#java.io.InputStream/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/input-stream.html +$dokka.location:com.uchuhimo.konf.source.js/JsProvider/reader/#java.io.Reader/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-provider/reader.html +$dokka.location:com.uchuhimo.konf.source.js/JsWriter///PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/index.html +$dokka.location:com.uchuhimo.konf.source.js/JsWriter/JsWriter/#com.uchuhimo.konf.Config/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/-js-writer.html +$dokka.location:com.uchuhimo.konf.source.js/JsWriter/config/#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/config.html +$dokka.location:com.uchuhimo.konf.source.js/JsWriter/toOutputStream/#java.io.OutputStream/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/to-output-stream.html +$dokka.location:com.uchuhimo.konf.source.js/JsWriter/toWriter/#java.io.Writer/PointingToDeclaration/konf-js/com.uchuhimo.konf.source.js/-js-writer/to-writer.html +$dokka.location:com.uchuhimo.konf.source////PointingToDeclaration/konf-js/com.uchuhimo.konf.source/index.html +$dokka.location:com.uchuhimo.konf.source//js/com.uchuhimo.konf.source.DefaultLoaders#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source/js.html +$dokka.location:com.uchuhimo.konf.source//js/com.uchuhimo.konf.source.DefaultProviders#/PointingToDeclaration/konf-js/com.uchuhimo.konf.source/js.html +com.uchuhimo.konf.source +com.uchuhimo.konf.source.js + diff --git a/dokka-cache/org.graphstream/gs-algo/2.0.list b/dokka-cache/org.graphstream/gs-algo/2.0.list deleted file mode 100644 index 89667fb1b1..0000000000 --- a/dokka-cache/org.graphstream/gs-algo/2.0.list +++ /dev/null @@ -1,11 +0,0 @@ -org.graphstream.algorithm -org.graphstream.algorithm.coloring -org.graphstream.algorithm.community -org.graphstream.algorithm.flow -org.graphstream.algorithm.generator -org.graphstream.algorithm.generator.lcf -org.graphstream.algorithm.measure -org.graphstream.algorithm.networksimplex -org.graphstream.algorithm.randomWalk -org.graphstream.algorithm.util -org.graphstream.ui.layout diff --git a/dokka-cache/org.mapsforge/mapsforge-map-awt/0.25.0.list b/dokka-cache/org.mapsforge/mapsforge-map-awt/0.25.0.list deleted file mode 100644 index 155e695552..0000000000 --- a/dokka-cache/org.mapsforge/mapsforge-map-awt/0.25.0.list +++ /dev/null @@ -1,4 +0,0 @@ -org.mapsforge.map.awt.graphics -org.mapsforge.map.awt.input -org.mapsforge.map.awt.util -org.mapsforge.map.awt.view From ba8b1865dd9a04c2543f543856493d0554022acf Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 16:31:43 +0000 Subject: [PATCH 075/196] chore(build): update the javadoc.io cache --- .../logback-classic/1.5.21.list | 29 ++ .../caffeine/3.2.3.list | 3 - .../alchemist-swingui/42.3.18.list | 430 ++++++++++++++++++ dokka-cache/org.antlr/antlr4/4.13.2.list | 16 - dokka-cache/org.graphstream/gs-algo/2.0.list | 11 + .../mapsforge-map-awt/0.25.0.list | 4 + dokka-cache/org.yaml/snakeyaml/2.5.list | 20 - 7 files changed, 474 insertions(+), 39 deletions(-) create mode 100644 dokka-cache/ch.qos.logback/logback-classic/1.5.21.list delete mode 100644 dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list create mode 100644 dokka-cache/it.unibo.alchemist/alchemist-swingui/42.3.18.list delete mode 100644 dokka-cache/org.antlr/antlr4/4.13.2.list create mode 100644 dokka-cache/org.graphstream/gs-algo/2.0.list create mode 100644 dokka-cache/org.mapsforge/mapsforge-map-awt/0.25.0.list delete mode 100644 dokka-cache/org.yaml/snakeyaml/2.5.list diff --git a/dokka-cache/ch.qos.logback/logback-classic/1.5.21.list b/dokka-cache/ch.qos.logback/logback-classic/1.5.21.list new file mode 100644 index 0000000000..eacb1257cb --- /dev/null +++ b/dokka-cache/ch.qos.logback/logback-classic/1.5.21.list @@ -0,0 +1,29 @@ +module:ch.qos.logback.classic +ch.qos.logback.classic +ch.qos.logback.classic.boolex +ch.qos.logback.classic.encoder +ch.qos.logback.classic.filter +ch.qos.logback.classic.helpers +ch.qos.logback.classic.html +ch.qos.logback.classic.joran +ch.qos.logback.classic.joran.action +ch.qos.logback.classic.joran.sanity +ch.qos.logback.classic.joran.serializedModel +ch.qos.logback.classic.jul +ch.qos.logback.classic.layout +ch.qos.logback.classic.log4j +ch.qos.logback.classic.model +ch.qos.logback.classic.model.processor +ch.qos.logback.classic.model.util +ch.qos.logback.classic.net +ch.qos.logback.classic.net.server +ch.qos.logback.classic.pattern +ch.qos.logback.classic.pattern.color +ch.qos.logback.classic.selector +ch.qos.logback.classic.selector.servlet +ch.qos.logback.classic.servlet +ch.qos.logback.classic.sift +ch.qos.logback.classic.spi +ch.qos.logback.classic.turbo +ch.qos.logback.classic.tyler +ch.qos.logback.classic.util diff --git a/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list b/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list deleted file mode 100644 index ae20519915..0000000000 --- a/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list +++ /dev/null @@ -1,3 +0,0 @@ -module:com.github.benmanes.caffeine -com.github.benmanes.caffeine.cache -com.github.benmanes.caffeine.cache.stats diff --git a/dokka-cache/it.unibo.alchemist/alchemist-swingui/42.3.18.list b/dokka-cache/it.unibo.alchemist/alchemist-swingui/42.3.18.list new file mode 100644 index 0000000000..9e53e1a1f1 --- /dev/null +++ b/dokka-cache/it.unibo.alchemist/alchemist-swingui/42.3.18.list @@ -0,0 +1,430 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:it.unibo.alchemist.boundary.swingui.api////PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/Graphical2DOutputMonitor///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical2-d-output-monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/Graphical2DOutputMonitor/zoomTo/#P#double/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical2-d-output-monitor/zoom-to.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/GraphicalOutputMonitor///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical-output-monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/GraphicalOutputMonitor/getStep/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical-output-monitor/get-step.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/GraphicalOutputMonitor/isRealTime/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical-output-monitor/is-real-time.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/GraphicalOutputMonitor/repaint/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical-output-monitor/repaint.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/GraphicalOutputMonitor/setDrawLinks/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical-output-monitor/set-draw-links.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/GraphicalOutputMonitor/setEffectStack/#java.util.List/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical-output-monitor/set-effect-stack.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/GraphicalOutputMonitor/setMarkCloserNode/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical-output-monitor/set-mark-closer-node.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/GraphicalOutputMonitor/setRealTime/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical-output-monitor/set-real-time.html +$dokka.location:it.unibo.alchemist.boundary.swingui.api/GraphicalOutputMonitor/setStep/#int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.api/-graphical-output-monitor/set-step.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api////PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/DrawLayers///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-draw-layers/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/DrawLayers/drawLayers/#java.util.Collection>#it.unibo.alchemist.model.Environment#java.awt.Graphics2D#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-draw-layers/draw-layers.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/Effect///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-effect/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/Effect/apply/#java.awt.Graphics2D#it.unibo.alchemist.model.Node#int#int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-effect/apply.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/Effect/apply/#java.awt.Graphics2D#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Environment#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-effect/apply.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/Effect/equals/#java.lang.Object/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-effect/equals.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/Effect/getColorSummary/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-effect/get-color-summary.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/Effect/hashCode/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-effect/hash-code.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/FunctionDrawer///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-function-drawer/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/FunctionDrawer/drawFunction/#java.util.function.Function#it.unibo.alchemist.model.Environment#java.awt.Graphics2D#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-function-drawer/draw-function.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/LayerToFunctionMapper///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-layer-to-function-mapper/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/LayerToFunctionMapper/map/#java.util.stream.Stream[it.unibo.alchemist.model.Layer[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-layer-to-function-mapper/map.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/LayerToFunctionMapper/map/#kotlin.collections.Collection[it.unibo.alchemist.model.Layer[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-layer-to-function-mapper/map.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.api/LayerToFunctionMapper/prepare/#it.unibo.alchemist.boundary.swingui.effect.impl.AbstractDrawLayersValues#kotlin.collections.Collection[it.unibo.alchemist.model.Layer[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]#java.awt.Graphics2D#it.unibo.alchemist.boundary.ui.api.Wormhole2D[TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.api/-layer-to-function-mapper/prepare.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl////PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers/AbstractDrawLayers/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/-abstract-draw-layers.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers/alpha/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/alpha.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers/blue/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/blue.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers/drawLayers/#java.util.Collection>#it.unibo.alchemist.model.Environment#java.awt.Graphics2D#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/draw-layers.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers/getColorSummary/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/get-color-summary.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers/green/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/green.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers/isLayerFilter/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/is-layer-filter.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers/molString/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/mol-string.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers/red/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/red.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayers/setLayerFilter/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers/set-layer-filter.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayersGradient///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers-gradient/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayersGradient/drawFunction/#java.util.function.Function#it.unibo.alchemist.model.Environment#java.awt.Graphics2D#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers-gradient/draw-function.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayersGradient/map/#double#double#double#double#double/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers-gradient/map.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayersGradient/samples/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers-gradient/samples.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayersValues///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers-values/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayersValues/drawFunction/#java.util.function.Function#it.unibo.alchemist.model.Environment#java.awt.Graphics2D#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers-values/draw-function.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayersValues/drawLayers/#java.util.Collection>#it.unibo.alchemist.model.Environment#java.awt.Graphics2D#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers-values/draw-layers.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayersValues/maxLayerValue/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers-values/max-layer-value.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawLayersValues/minLayerValue/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-layers-values/min-layer-value.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawOnce///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-once/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawOnce/AbstractDrawOnce/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-once/-abstract-draw-once.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawOnce/apply/#java.awt.Graphics2D#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Environment#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-once/apply.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractDrawOnce/markerNodeID/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstract-draw-once/marker-node-i-d.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines.Distribution.LINEAR///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/-distribution/-l-i-n-e-a-r/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines.Distribution.LOGARITHMIC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/-distribution/-l-o-g-a-r-i-t-h-m-i-c/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines.Distribution///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/-distribution/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines.Distribution/toString/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/-distribution/to-string.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines.Distribution/valueOf/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/-distribution/value-of.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines.Distribution/values/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/-distribution/values.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines/AbstractrDrawLayersIsolines/#it.unibo.alchemist.boundary.swingui.effect.isolines.api.IsolinesFinder#it.unibo.alchemist.boundary.swingui.effect.api.LayerToFunctionMapper/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/-abstractr-draw-layers-isolines.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines/distribution/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/distribution.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines/drawFunction/#java.util.function.Function#it.unibo.alchemist.model.Environment#java.awt.Graphics2D#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/draw-function.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines/getDrawValues/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/get-draw-values.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines/getNumberOfIsolines/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/get-number-of-isolines.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines/linspace/#double#double#int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/linspace.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines/logspace/#double#double#int#double/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/logspace.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines/setDrawValues/#java.lang.Boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/set-draw-values.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/AbstractrDrawLayersIsolines/setNumberOfIsolines/#org.danilopianini.lang.RangedInteger/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-abstractr-draw-layers-isolines/set-number-of-isolines.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/BidimensionalGaussianLayersMapper.Companion///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-bidimensional-gaussian-layers-mapper/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/BidimensionalGaussianLayersMapper.Companion/MINIMUM_LAYER_VALUE/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-bidimensional-gaussian-layers-mapper/-companion/-m-i-n-i-m-u-m_-l-a-y-e-r_-v-a-l-u-e.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/BidimensionalGaussianLayersMapper///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-bidimensional-gaussian-layers-mapper/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/BidimensionalGaussianLayersMapper/BidimensionalGaussianLayersMapper/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-bidimensional-gaussian-layers-mapper/-bidimensional-gaussian-layers-mapper.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/BidimensionalGaussianLayersMapper/map/#java.util.stream.Stream[it.unibo.alchemist.model.Layer[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-bidimensional-gaussian-layers-mapper/map.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/BidimensionalGaussianLayersMapper/map/#kotlin.collections.Collection[it.unibo.alchemist.model.Layer[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-bidimensional-gaussian-layers-mapper/map.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/BidimensionalGaussianLayersMapper/prepare/#it.unibo.alchemist.boundary.swingui.effect.impl.AbstractDrawLayersValues#kotlin.collections.Collection[it.unibo.alchemist.model.Layer[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]#java.awt.Graphics2D#it.unibo.alchemist.boundary.ui.api.Wormhole2D[TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-bidimensional-gaussian-layers-mapper/prepare.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawBidimensionalGaussianLayersGradient///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-bidimensional-gaussian-layers-gradient/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawBidimensionalGaussianLayersGradient/DrawBidimensionalGaussianLayersGradient/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-bidimensional-gaussian-layers-gradient/-draw-bidimensional-gaussian-layers-gradient.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawBidimensionalGaussianLayersIsolines///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-bidimensional-gaussian-layers-isolines/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawBidimensionalGaussianLayersIsolines/DrawBidimensionalGaussianLayersIsolines/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-bidimensional-gaussian-layers-isolines/-draw-bidimensional-gaussian-layers-isolines.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawCognitiveMap///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-cognitive-map/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawCognitiveMap/DrawCognitiveMap/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-cognitive-map/-draw-cognitive-map.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawCognitiveMap/alpha/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-cognitive-map/alpha.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawCognitiveMap/apply/#java.awt.Graphics2D#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Environment#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-cognitive-map/apply.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawCognitiveMap/blue/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-cognitive-map/blue.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawCognitiveMap/getColorSummary/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-cognitive-map/get-color-summary.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawCognitiveMap/green/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-cognitive-map/green.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawCognitiveMap/red/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-cognitive-map/red.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawDirectedNode///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-directed-node/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawDirectedNode/DrawDirectedNode/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-directed-node/-draw-directed-node.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawDirectedNode/apply/#java.awt.Graphics2D#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any])]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]#it.unibo.alchemist.boundary.ui.api.Wormhole2D[TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-directed-node/apply.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawDirectedNode/colorSummary/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-directed-node/color-summary.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawDirectedNode/getColorSummary/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-directed-node/get-color-summary.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawNavigationGraph///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-navigation-graph/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawNavigationGraph/DrawNavigationGraph/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-navigation-graph/-draw-navigation-graph.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawNavigationGraph/alpha/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-navigation-graph/alpha.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawNavigationGraph/blue/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-navigation-graph/blue.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawNavigationGraph/getColorSummary/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-navigation-graph/get-color-summary.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawNavigationGraph/green/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-navigation-graph/green.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawNavigationGraph/red/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-navigation-graph/red.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawPedestrianPath///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-pedestrian-path/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawPedestrianPath/DrawPedestrianPath/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-pedestrian-path/-draw-pedestrian-path.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawPedestrianPath/alpha/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-pedestrian-path/alpha.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawPedestrianPath/blue/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-pedestrian-path/blue.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawPedestrianPath/getColorSummary/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-pedestrian-path/get-color-summary.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawPedestrianPath/green/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-pedestrian-path/green.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawPedestrianPath/isToBeDrawn/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-pedestrian-path/is-to-be-drawn.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawPedestrianPath/red/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-pedestrian-path/red.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawPedestrianPath/setToBeDrawn/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-pedestrian-path/set-to-be-drawn.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape.Mode.DRAW_ELLIPSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/-mode/-d-r-a-w_-e-l-l-i-p-s-e/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape.Mode.DRAW_RECTANGLE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/-mode/-d-r-a-w_-r-e-c-t-a-n-g-l-e/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape.Mode.FILL_ELLIPSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/-mode/-f-i-l-l_-e-l-l-i-p-s-e/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape.Mode.FILL_RECTANGLE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/-mode/-f-i-l-l_-r-e-c-t-a-n-g-l-e/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape.Mode///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/-mode/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape.Mode/toString/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/-mode/to-string.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape.Mode/valueOf/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/-mode/value-of.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape.Mode/values/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/-mode/values.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/DrawShape/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/-draw-shape.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/alpha/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/alpha.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/apply/#java.awt.Graphics2D#it.unibo.alchemist.model.Node#int#int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/apply.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/blue/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/blue.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/getColorChannel/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/get-color-channel.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/getColorSummary/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/get-color-summary.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/getIncarnation/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/get-incarnation.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/green/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/green.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/isMolFilter/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/is-mol-filter.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/isMolPropertyFilter/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/is-mol-property-filter.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/isReverse/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/is-reverse.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/isWritingPropertyValue/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/is-writing-property-value.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/maxprop/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/maxprop.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/minprop/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/minprop.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/mode/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/mode.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/molString/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/mol-string.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/molecule/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/molecule.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/property/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/property.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/propoom/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/propoom.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/red/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/red.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/scaleFactor/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/scale-factor.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/setC/#it.unibo.alchemist.boundary.swingui.impl.ColorChannel/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/set-c.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/setIncarnation/#org.danilopianini.lang.CollectionWithCurrentElement/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/set-incarnation.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/setMolFilter/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/set-mol-filter.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/setMolPropertyFilter/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/set-mol-property-filter.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/setReverse/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/set-reverse.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/setWritingPropertyValue/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/set-writing-property-value.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawShape/size/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-shape/size.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawSmartcam///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-smartcam/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawSmartcam/DrawSmartcam/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-smartcam/-draw-smartcam.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawSmartcam/apply/#java.awt.Graphics2D#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Environment#it.unibo.alchemist.boundary.ui.api.Wormhole2D

/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-smartcam/apply.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/DrawSmartcam/getColorSummary/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-draw-smartcam/get-color-summary.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectBuilder///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-builder/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectBuilder/EffectBuilder/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-builder/-effect-builder.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectBuilder/actionPerformed/#java.awt.event.ActionEvent/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-builder/action-performed.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectBuilder/getResult/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-builder/get-result.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectFactory///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-factory/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectFactory/buildDefaultEffect/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-factory/build-default-effect.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectFactory/buildEffect/#java.lang.Class/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-factory/build-effect.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectSerializationFactory///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-serialization-factory/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectSerializationFactory/effectToFile/#java.io.File#it.unibo.alchemist.boundary.swingui.effect.api.Effect/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-serialization-factory/effect-to-file.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectSerializationFactory/effectsFromFile/#java.io.File/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-serialization-factory/effects-from-file.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.impl/EffectSerializationFactory/effectsToFile/#java.io.File#java.util.List/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.impl/-effect-serialization-factory/effects-to-file.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api////PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/Isoline///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isoline/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/Isoline/getSegments/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isoline/get-segments.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/Isoline/getValue/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isoline/get-value.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFactory.IsolineFinders.CONREC///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-factory/-isoline-finders/-c-o-n-r-e-c/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFactory.IsolineFinders///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-factory/-isoline-finders/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFactory.IsolineFinders/valueOf/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-factory/-isoline-finders/value-of.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFactory.IsolineFinders/values/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-factory/-isoline-finders/values.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFactory///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-factory/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFactory/makeIsoline/#java.lang.Number#java.util.Collection/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-factory/make-isoline.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFactory/makeIsolinesFinder/#it.unibo.alchemist.boundary.swingui.effect.isolines.api.IsolinesFactory.IsolineFinders/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-factory/make-isolines-finder.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFactory/makeSegment/#java.lang.Number#java.lang.Number#java.lang.Number#java.lang.Number/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-factory/make-segment.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFinder///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-finder/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFinder/findIsolines/#java.util.function.BinaryOperator#it.unibo.alchemist.boundary.swingui.effect.isolines.api.Segment2D#java.util.Collection/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-finder/find-isolines.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/IsolinesFinder/findIsolines/#java.util.function.BinaryOperator#java.lang.Number#java.lang.Number#java.lang.Number#java.lang.Number#java.util.Collection/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-isolines-finder/find-isolines.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/Segment2D///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-segment2-d/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/Segment2D/getX1/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-segment2-d/get-x1.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/Segment2D/getX2/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-segment2-d/get-x2.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/Segment2D/getY1/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-segment2-d/get-y1.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.api/Segment2D/getY2/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.api/-segment2-d/get-y2.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.impl////PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.impl/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.impl/ConcreteIsolinesFactory///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.impl/-concrete-isolines-factory/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.impl/ConcreteIsolinesFactory/ConcreteIsolinesFactory/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.impl/-concrete-isolines-factory/-concrete-isolines-factory.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.impl/ConcreteIsolinesFactory/makeIsoline/#java.lang.Number#java.util.Collection/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.impl/-concrete-isolines-factory/make-isoline.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.impl/ConcreteIsolinesFactory/makeIsolinesFinder/#it.unibo.alchemist.boundary.swingui.effect.isolines.api.IsolinesFactory.IsolineFinders/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.impl/-concrete-isolines-factory/make-isolines-finder.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.impl/ConcreteIsolinesFactory/makeSegment/#java.lang.Number#java.lang.Number#java.lang.Number#java.lang.Number/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.impl/-concrete-isolines-factory/make-segment.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.impl/ConrecIsolinesFinder///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.impl/-conrec-isolines-finder/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.impl/ConrecIsolinesFinder/ConrecIsolinesFinder/#it.unibo.alchemist.boundary.swingui.effect.isolines.api.IsolinesFactory/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.impl/-conrec-isolines-finder/-conrec-isolines-finder.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.impl/ConrecIsolinesFinder/findIsolines/#java.util.function.BinaryOperator#it.unibo.alchemist.boundary.swingui.effect.isolines.api.Segment2D#java.util.Collection/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.impl/-conrec-isolines-finder/find-isolines.html +$dokka.location:it.unibo.alchemist.boundary.swingui.effect.isolines.impl/ConrecIsolinesFinder/findIsolines/#java.util.function.BinaryOperator#java.lang.Number#java.lang.Number#java.lang.Number#java.lang.Number#java.util.Collection/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.effect.isolines.impl/-conrec-isolines-finder/find-isolines.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl////PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/AbstractMenu///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-abstract-menu/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/AbstractMenu/AbstractMenu/#java.lang.String#javax.swing.JMenuItem[]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-abstract-menu/-abstract-menu.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/AbstractMenu/addActionListener/#java.awt.event.ActionListener/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-abstract-menu/add-action-listener.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/AlchemistSwingUI///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-alchemist-swing-u-i/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/AlchemistSwingUI/AlchemistSwingUI/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-alchemist-swing-u-i/-alchemist-swing-u-i.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/AlchemistSwingUI/DEFAULT_ICON_SIZE/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-alchemist-swing-u-i/-d-e-f-a-u-l-t_-i-c-o-n_-s-i-z-e.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/AlchemistSwingUI/loadScaledImage/#java.lang.String#int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-alchemist-swing-u-i/load-scaled-image.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/AlchemistSwingUI/loadScaledImage/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-alchemist-swing-u-i/load-scaled-image.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel.ALPHA///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/-a-l-p-h-a/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel.BLUE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/-b-l-u-e/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel.BRIGHTNESS///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/-b-r-i-g-h-t-n-e-s-s/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel.GREEN///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/-g-r-e-e-n/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel.HUE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/-h-u-e/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel.RED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/-r-e-d/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel.SATURATION///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/-s-a-t-u-r-a-t-i-o-n/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel/alter/#java.awt.Color#float/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/alter.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel/valueOf/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/value-of.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ColorChannel/values/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-color-channel/values.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/FileMenu///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-file-menu/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/FileMenu/FileMenu/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-file-menu/-file-menu.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/FileMenu/actionPerformed/#java.awt.event.ActionEvent/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-file-menu/action-performed.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/LocalizedResourceBundle///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-localized-resource-bundle/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/LocalizedResourceBundle/get/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-localized-resource-bundle/get.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/LocalizedResourceBundle/get/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-localized-resource-bundle/get.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/LocalizedResourceBundle/getString/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-localized-resource-bundle/get-string.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/NumericTextField///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-numeric-text-field/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/NumericTextField/NumericTextField/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-numeric-text-field/-numeric-text-field.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel.Status.MAX_REACTIVITY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/-status/-m-a-x_-r-e-a-c-t-i-v-i-t-y/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel.Status.REAL_TIME///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/-status/-r-e-a-l_-t-i-m-e/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel.Status.USER_SELECTED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/-status/-u-s-e-r_-s-e-l-e-c-t-e-d/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel.Status///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/-status/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel.Status/valueOf/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/-status/value-of.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel.Status/values/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/-status/values.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel/ReactivityPanel/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/-reactivity-panel.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel/addActionListener/#java.awt.event.ActionListener/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/add-action-listener.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel/addChangeLister/#javax.swing.event.ChangeListener/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/add-change-lister.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel/getUserReactivity/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/get-user-reactivity.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel/itemStateChanged/#java.awt.event.ItemEvent/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/item-state-changed.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel/setActionCommand/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/set-action-command.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/ReactivityPanel/status/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-reactivity-panel/status.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlButton///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-button/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlButton/SimControlButton/#java.lang.String#java.lang.Enum#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-button/-sim-control-button.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlCommand.PAUSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-command/-p-a-u-s-e/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlCommand.PLAY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-command/-p-l-a-y/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlCommand.STEP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-command/-s-t-e-p/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlCommand.STOP///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-command/-s-t-o-p/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlCommand///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-command/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlCommand/createButton/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-command/create-button.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlCommand/equalsToString/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-command/equals-to-string.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlCommand/valueOf/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-command/value-of.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlCommand/values/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-command/values.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlPanel///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-panel/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlPanel/addActionListener/#java.awt.event.ActionListener/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-panel/add-action-listener.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlPanel/createControlPanel/#it.unibo.alchemist.core.Simulation/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-panel/create-control-panel.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlPanel/getSimulation/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-panel/get-simulation.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlPanel/isDown/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-panel/is-down.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlPanel/setButtonEnabled/#it.unibo.alchemist.boundary.swingui.impl.SimControlCommand#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-panel/set-button-enabled.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlPanel/setEnabled/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-panel/set-enabled.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlPanel/setSimulation/#it.unibo.alchemist.core.Simulation/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-panel/set-simulation.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlPanel/shutdown/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-panel/shutdown.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/SimControlPanel/toString/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-sim-control-panel/to-string.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/StatusBar///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-status-bar/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/StatusBar/StatusBar/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-status-bar/-status-bar.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/StatusBar/setNo/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-status-bar/set-no.html +$dokka.location:it.unibo.alchemist.boundary.swingui.impl/StatusBar/setOK/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.impl/-status-bar/set-o-k.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl////PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/DEFAULT_FRAME_RATE/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/-d-e-f-a-u-l-t_-f-r-a-m-e_-r-a-t-e.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/Generic2DDisplay/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/-generic2-d-display.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/Generic2DDisplay/#int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/-generic2-d-display.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/finished/#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Time#long/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/finished.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/getStep/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/get-step.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/initialized/#it.unibo.alchemist.model.Environment/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/initialized.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/isRealTime/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/is-real-time.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/repaint/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/repaint.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/setDrawLinks/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/set-draw-links.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/setEffectStack/#java.util.List/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/set-effect-stack.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/setMarkCloserNode/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/set-mark-closer-node.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/setRealTime/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/set-real-time.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/setStep/#int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/set-step.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/stepDone/#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Actionable#it.unibo.alchemist.model.Time#long/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/step-done.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/Generic2DDisplay/zoomTo/#P#double/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-generic2-d-display/zoom-to.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/MapDisplay///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-map-display/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/MapDisplay/MapDisplay/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-map-display/-map-display.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/MapDisplay/finished/#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Time#long/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-map-display/finished.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/MapDisplay/initialized/#it.unibo.alchemist.model.Environment/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-map-display/initialized.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/MapDisplay/paint/#java.awt.Graphics/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-map-display/paint.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/MoleculeInjectorGUI///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-molecule-injector-g-u-i/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/MoleculeInjectorGUI/MoleculeInjectorGUI/#java.util.Set>/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-molecule-injector-g-u-i/-molecule-injector-g-u-i.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/NodeTracker///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-node-tracker/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/NodeTracker/NodeTracker/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-node-tracker/-node-tracker.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/NodeTracker/actionPerformed/#java.awt.event.ActionEvent/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-node-tracker/action-performed.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/NodeTracker/finished/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-node-tracker/finished.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/NodeTracker/initialized/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-node-tracker/initialized.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/NodeTracker/stepDone/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Actionable[TypeParam(bounds=[kotlin.Any?])]?#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-node-tracker/step-done.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/SwingGUI///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-swing-g-u-i/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/SwingGUI/SwingGUI/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]#java.io.File?#kotlin.Boolean#kotlin.Int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-swing-g-u-i/-swing-g-u-i.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/SwingGUI/SwingGUI/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]#kotlin.String?#kotlin.Boolean#kotlin.Int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-swing-g-u-i/-swing-g-u-i.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/SwingGUI/environment/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-swing-g-u-i/environment.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/SwingGUI/finished/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-swing-g-u-i/finished.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/SwingGUI/initialized/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-swing-g-u-i/initialized.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/SwingGUI/isRealTime/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-swing-g-u-i/is-real-time.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/SwingGUI/step/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-swing-g-u-i/step.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/SwingGUI/stepDone/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position2D[^]])]#it.unibo.alchemist.model.Actionable[TypeParam(bounds=[kotlin.Any?])]?#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-swing-g-u-i/step-done.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/TimeStepMonitor///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-time-step-monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/TimeStepMonitor/TimeStepMonitor/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-time-step-monitor/-time-step-monitor.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/TimeStepMonitor/finished/#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Time#long/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-time-step-monitor/finished.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/TimeStepMonitor/initialized/#it.unibo.alchemist.model.Environment/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-time-step-monitor/initialized.html +$dokka.location:it.unibo.alchemist.boundary.swingui.monitor.impl/TimeStepMonitor/stepDone/#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Actionable#it.unibo.alchemist.model.Time#long/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.monitor.impl/-time-step-monitor/step-done.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl////PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/AbstractFlowLayout/#int#int#int#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/-abstract-flow-layout.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/BOTH/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/-b-o-t-h.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/CENTER/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/-c-e-n-t-e-r.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/LEFT/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/-l-e-f-t.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/RIGHT/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/-r-i-g-h-t.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/TOP/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/-t-o-p.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/addLayoutComponent/#java.lang.String#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/add-layout-component.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/getComponentOrder/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/get-component-order.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/getComponentsList/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/get-components-list.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/isOrdered/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/is-ordered.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/layoutContainer/#java.awt.Container/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/layout-container.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/minimumLayoutSize/#java.awt.Container/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/minimum-layout-size.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/preferredLayoutSize/#java.awt.Container/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/preferred-layout-size.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/removeLayoutComponent/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/remove-layout-component.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/setComponentOrder/#java.awt.Component#int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/set-component-order.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractFlowLayout/toString/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-flow-layout/to-string.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractJTapeSection///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-j-tape-section/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractJTapeSection/AbstractJTapeSection/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-j-tape-section/-abstract-j-tape-section.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractJTapeSection/registerFeature/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-j-tape-section/register-feature.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/AbstractJTapeSection/unregisterFeature/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-abstract-j-tape-section/unregister-feature.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/HorizontalFlowLayout///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-horizontal-flow-layout/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/HorizontalFlowLayout/HorizontalFlowLayout/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-horizontal-flow-layout/-horizontal-flow-layout.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/HorizontalFlowLayout/HorizontalFlowLayout/#int#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-horizontal-flow-layout/-horizontal-flow-layout.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/HorizontalFlowLayout/HorizontalFlowLayout/#int#int#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-horizontal-flow-layout/-horizontal-flow-layout.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/HorizontalFlowLayout/HorizontalFlowLayout/#int#int#int#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-horizontal-flow-layout/-horizontal-flow-layout.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/HorizontalFlowLayout/layoutContainer/#java.awt.Container/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-horizontal-flow-layout/layout-container.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectRepresentation///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effect-representation/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectRepresentation/JEffectRepresentation/#it.unibo.alchemist.boundary.swingui.effect.api.Effect#it.unibo.alchemist.boundary.swingui.api.GraphicalOutputMonitor/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effect-representation/-j-effect-representation.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectRepresentation/addItemListener/#java.awt.event.ItemListener/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effect-representation/add-item-listener.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectRepresentation/effect/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effect-representation/effect.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectRepresentation/getSelectedObjects/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effect-representation/get-selected-objects.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectRepresentation/isSelected/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effect-representation/is-selected.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectRepresentation/removeItemListener/#java.awt.event.ItemListener/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effect-representation/remove-item-listener.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectRepresentation/setEnabled/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effect-representation/set-enabled.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectRepresentation/setSelected/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effect-representation/set-selected.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectsTab///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effects-tab/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectsTab/JEffectsTab/#it.unibo.alchemist.boundary.swingui.api.GraphicalOutputMonitor#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effects-tab/-j-effects-tab.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectsTab/addActionListener/#java.awt.event.ActionListener/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effects-tab/add-action-listener.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectsTab/addEffect/#it.unibo.alchemist.boundary.swingui.effect.api.Effect/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effects-tab/add-effect.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectsTab/clearEffects/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effects-tab/clear-effects.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectsTab/getEffects/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effects-tab/get-effects.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectsTab/itemStateChanged/#java.awt.event.ItemEvent/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effects-tab/item-state-changed.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectsTab/setEffects/#java.util.List/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effects-tab/set-effects.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JEffectsTab/setEnabled/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-effects-tab/set-enabled.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTape///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTape/JTape/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape/-j-tape.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTape/deregisterTab/#it.unibo.alchemist.boundary.swingui.tape.impl.JTapeTab/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape/deregister-tab.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTape/registerTab/#it.unibo.alchemist.boundary.swingui.tape.impl.JTapeTab/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape/register-tab.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack.Type.HORIZONTAL_STACK///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/-type/-h-o-r-i-z-o-n-t-a-l_-s-t-a-c-k/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack.Type.VERTICAL_STACK///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/-type/-v-e-r-t-i-c-a-l_-s-t-a-c-k/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack.Type///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/-type/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack.Type/valueOf/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/-type/value-of.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack.Type/values/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/-type/values.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack/JTapeFeatureStack/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/-j-tape-feature-stack.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack/JTapeFeatureStack/#it.unibo.alchemist.boundary.swingui.tape.impl.JTapeFeatureStack.Type/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/-j-tape-feature-stack.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack/add/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/add.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack/getLayout/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/get-layout.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack/getOrderedComponents/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/get-ordered-components.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack/registerFeature/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/register-feature.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack/remove/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/remove.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack/setComponentOrder/#java.awt.Component#int/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/set-component-order.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack/type/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/type.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeFeatureStack/unregisterFeature/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-feature-stack/unregister-feature.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeGroup///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-group/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeGroup/JTapeGroup/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-group/-j-tape-group.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeGroup/getDescription/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-group/get-description.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeGroup/registerSection/#it.unibo.alchemist.boundary.swingui.tape.impl.AbstractJTapeSection/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-group/register-section.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeGroup/setDescription/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-group/set-description.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeMainFeature///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-main-feature/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeMainFeature/JTapeMainFeature/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-main-feature/-j-tape-main-feature.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeMainFeature/registerFeature/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-main-feature/register-feature.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeMainFeature/unregisterFeature/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-main-feature/unregister-feature.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeTab///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-tab/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeTab/JTapeTab/#java.lang.String/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-tab/-j-tape-tab.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeTab/registerGroup/#it.unibo.alchemist.boundary.swingui.tape.impl.JTapeGroup/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-tab/register-group.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/JTapeTab/title/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-j-tape-tab/title.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/VerticalFlowLayout///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-vertical-flow-layout/index.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/VerticalFlowLayout/VerticalFlowLayout/#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-vertical-flow-layout/-vertical-flow-layout.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/VerticalFlowLayout/VerticalFlowLayout/#int#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-vertical-flow-layout/-vertical-flow-layout.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/VerticalFlowLayout/VerticalFlowLayout/#int#int#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-vertical-flow-layout/-vertical-flow-layout.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/VerticalFlowLayout/VerticalFlowLayout/#int#int#int#boolean/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-vertical-flow-layout/-vertical-flow-layout.html +$dokka.location:it.unibo.alchemist.boundary.swingui.tape.impl/VerticalFlowLayout/layoutContainer/#java.awt.Container/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.swingui.tape.impl/-vertical-flow-layout/layout-container.html +$dokka.location:it.unibo.alchemist.boundary.util////PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.util/index.html +$dokka.location:it.unibo.alchemist.boundary.util/InitMapsForge///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.util/-init-maps-forge/index.html +$dokka.location:it.unibo.alchemist.boundary.util/InitMapsForge/initAgent/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.util/-init-maps-forge/init-agent.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl////PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/index.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/AngleManagerImpl///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-angle-manager-impl/index.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/AngleManagerImpl/AngleManagerImpl/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-angle-manager-impl/-angle-manager-impl.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/AngleManagerImpl/AngleManagerImpl/#double#double/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-angle-manager-impl/-angle-manager-impl.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/AngleManagerImpl/AngleManagerImpl/#double/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-angle-manager-impl/-angle-manager-impl.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/AngleManagerImpl/DEF_DEG_PER_PIXEL/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-angle-manager-impl/-d-e-f_-d-e-g_-p-e-r_-p-i-x-e-l.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/AngleManagerImpl/getAngle/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-angle-manager-impl/get-angle.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/ComponentViewPort///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-component-view-port/index.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/ComponentViewPort/ComponentViewPort/#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-component-view-port/-component-view-port.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/ComponentViewPort/component/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-component-view-port/component.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/ComponentViewPort/equals/#java.lang.Object/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-component-view-port/equals.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/ComponentViewPort/getHeight/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-component-view-port/get-height.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/ComponentViewPort/getWidth/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-component-view-port/get-width.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/ComponentViewPort/hashCode/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-component-view-port/hash-code.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/index.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/MAX_ZOOM/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/-m-a-x_-z-o-o-m.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/MapWormhole/#it.unibo.alchemist.model.Environment#java.awt.Component#org.mapsforge.map.model.MapViewPosition/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/-map-wormhole.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/getEnvPoint/#java.awt.Point/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/get-env-point.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/getViewPoint/#it.unibo.alchemist.model.GeoPosition/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/get-view-point.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/getViewPosition/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/get-view-position.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/optimalZoom/#/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/optimal-zoom.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/rotateAroundPoint/#java.awt.Point#double/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/rotate-around-point.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/setEnvPosition/#it.unibo.alchemist.model.GeoPosition/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/set-env-position.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/setViewPosition/#java.awt.Point/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/set-view-position.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/setZoom/#double/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/set-zoom.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/MapWormhole/zoomOnPoint/#java.awt.Point#double/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-map-wormhole/zoom-on-point.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/WormholeSwing///PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-wormhole-swing/index.html +$dokka.location:it.unibo.alchemist.boundary.wormhole.impl/WormholeSwing/WormholeSwing/#it.unibo.alchemist.model.Environment#java.awt.Component/PointingToDeclaration/alchemist-swingui/it.unibo.alchemist.boundary.wormhole.impl/-wormhole-swing/-wormhole-swing.html +it.unibo.alchemist.boundary.swingui.api +it.unibo.alchemist.boundary.swingui.effect.api +it.unibo.alchemist.boundary.swingui.effect.impl +it.unibo.alchemist.boundary.swingui.effect.isolines.api +it.unibo.alchemist.boundary.swingui.effect.isolines.impl +it.unibo.alchemist.boundary.swingui.impl +it.unibo.alchemist.boundary.swingui.monitor.impl +it.unibo.alchemist.boundary.swingui.tape.impl +it.unibo.alchemist.boundary.util +it.unibo.alchemist.boundary.wormhole.impl diff --git a/dokka-cache/org.antlr/antlr4/4.13.2.list b/dokka-cache/org.antlr/antlr4/4.13.2.list deleted file mode 100644 index 7529bdba66..0000000000 --- a/dokka-cache/org.antlr/antlr4/4.13.2.list +++ /dev/null @@ -1,16 +0,0 @@ -org.antlr.v4 -org.antlr.v4.analysis -org.antlr.v4.automata -org.antlr.v4.codegen -org.antlr.v4.codegen.model -org.antlr.v4.codegen.model.chunk -org.antlr.v4.codegen.model.decl -org.antlr.v4.codegen.target -org.antlr.v4.gui -org.antlr.v4.misc -org.antlr.v4.parse -org.antlr.v4.semantics -org.antlr.v4.tool -org.antlr.v4.tool.ast -org.antlr.v4.unicode -src.org.antlr.v4.unicode diff --git a/dokka-cache/org.graphstream/gs-algo/2.0.list b/dokka-cache/org.graphstream/gs-algo/2.0.list new file mode 100644 index 0000000000..89667fb1b1 --- /dev/null +++ b/dokka-cache/org.graphstream/gs-algo/2.0.list @@ -0,0 +1,11 @@ +org.graphstream.algorithm +org.graphstream.algorithm.coloring +org.graphstream.algorithm.community +org.graphstream.algorithm.flow +org.graphstream.algorithm.generator +org.graphstream.algorithm.generator.lcf +org.graphstream.algorithm.measure +org.graphstream.algorithm.networksimplex +org.graphstream.algorithm.randomWalk +org.graphstream.algorithm.util +org.graphstream.ui.layout diff --git a/dokka-cache/org.mapsforge/mapsforge-map-awt/0.25.0.list b/dokka-cache/org.mapsforge/mapsforge-map-awt/0.25.0.list new file mode 100644 index 0000000000..155e695552 --- /dev/null +++ b/dokka-cache/org.mapsforge/mapsforge-map-awt/0.25.0.list @@ -0,0 +1,4 @@ +org.mapsforge.map.awt.graphics +org.mapsforge.map.awt.input +org.mapsforge.map.awt.util +org.mapsforge.map.awt.view diff --git a/dokka-cache/org.yaml/snakeyaml/2.5.list b/dokka-cache/org.yaml/snakeyaml/2.5.list deleted file mode 100644 index 2c2f6ae4bd..0000000000 --- a/dokka-cache/org.yaml/snakeyaml/2.5.list +++ /dev/null @@ -1,20 +0,0 @@ -org.yaml.snakeyaml -org.yaml.snakeyaml.comments -org.yaml.snakeyaml.composer -org.yaml.snakeyaml.constructor -org.yaml.snakeyaml.emitter -org.yaml.snakeyaml.env -org.yaml.snakeyaml.error -org.yaml.snakeyaml.events -org.yaml.snakeyaml.extensions.compactnotation -org.yaml.snakeyaml.inspector -org.yaml.snakeyaml.introspector -org.yaml.snakeyaml.nodes -org.yaml.snakeyaml.parser -org.yaml.snakeyaml.reader -org.yaml.snakeyaml.representer -org.yaml.snakeyaml.resolver -org.yaml.snakeyaml.scanner -org.yaml.snakeyaml.serializer -org.yaml.snakeyaml.tokens -org.yaml.snakeyaml.util From 6103fb7377b22780a739671191ad36d6ba769213 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 16:50:11 +0000 Subject: [PATCH 076/196] chore(build): update the javadoc.io cache --- .../caffeine/3.2.3.list | 3 +++ dokka-cache/org.antlr/antlr4/4.13.2.list | 16 +++++++++++++++ dokka-cache/org.yaml/snakeyaml/2.5.list | 20 +++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list create mode 100644 dokka-cache/org.antlr/antlr4/4.13.2.list create mode 100644 dokka-cache/org.yaml/snakeyaml/2.5.list diff --git a/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list b/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list new file mode 100644 index 0000000000..ae20519915 --- /dev/null +++ b/dokka-cache/com.github.ben-manes.caffeine/caffeine/3.2.3.list @@ -0,0 +1,3 @@ +module:com.github.benmanes.caffeine +com.github.benmanes.caffeine.cache +com.github.benmanes.caffeine.cache.stats diff --git a/dokka-cache/org.antlr/antlr4/4.13.2.list b/dokka-cache/org.antlr/antlr4/4.13.2.list new file mode 100644 index 0000000000..7529bdba66 --- /dev/null +++ b/dokka-cache/org.antlr/antlr4/4.13.2.list @@ -0,0 +1,16 @@ +org.antlr.v4 +org.antlr.v4.analysis +org.antlr.v4.automata +org.antlr.v4.codegen +org.antlr.v4.codegen.model +org.antlr.v4.codegen.model.chunk +org.antlr.v4.codegen.model.decl +org.antlr.v4.codegen.target +org.antlr.v4.gui +org.antlr.v4.misc +org.antlr.v4.parse +org.antlr.v4.semantics +org.antlr.v4.tool +org.antlr.v4.tool.ast +org.antlr.v4.unicode +src.org.antlr.v4.unicode diff --git a/dokka-cache/org.yaml/snakeyaml/2.5.list b/dokka-cache/org.yaml/snakeyaml/2.5.list new file mode 100644 index 0000000000..2c2f6ae4bd --- /dev/null +++ b/dokka-cache/org.yaml/snakeyaml/2.5.list @@ -0,0 +1,20 @@ +org.yaml.snakeyaml +org.yaml.snakeyaml.comments +org.yaml.snakeyaml.composer +org.yaml.snakeyaml.constructor +org.yaml.snakeyaml.emitter +org.yaml.snakeyaml.env +org.yaml.snakeyaml.error +org.yaml.snakeyaml.events +org.yaml.snakeyaml.extensions.compactnotation +org.yaml.snakeyaml.inspector +org.yaml.snakeyaml.introspector +org.yaml.snakeyaml.nodes +org.yaml.snakeyaml.parser +org.yaml.snakeyaml.reader +org.yaml.snakeyaml.representer +org.yaml.snakeyaml.resolver +org.yaml.snakeyaml.scanner +org.yaml.snakeyaml.serializer +org.yaml.snakeyaml.tokens +org.yaml.snakeyaml.util From 6a6b0d7ad6f2cceb203cb3ca108f8ff45dec759c Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 17:40:06 +0000 Subject: [PATCH 077/196] chore(build): update the javadoc.io cache --- .../alchemist-graphql-surrogates/42.3.18.list | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 dokka-cache/it.unibo.alchemist/alchemist-graphql-surrogates/42.3.18.list diff --git a/dokka-cache/it.unibo.alchemist/alchemist-graphql-surrogates/42.3.18.list b/dokka-cache/it.unibo.alchemist/alchemist-graphql-surrogates/42.3.18.list new file mode 100644 index 0000000000..5acaa37b1e --- /dev/null +++ b/dokka-cache/it.unibo.alchemist/alchemist-graphql-surrogates/42.3.18.list @@ -0,0 +1,172 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:it.unibo.alchemist.boundary.graphql.monitor////PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.monitor/EnvironmentSubscriptionMonitor///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.monitor/-environment-subscription-monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.monitor/EnvironmentSubscriptionMonitor/EnvironmentSubscriptionMonitor/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.monitor/-environment-subscription-monitor/-environment-subscription-monitor.html +$dokka.location:it.unibo.alchemist.boundary.graphql.monitor/EnvironmentSubscriptionMonitor/eventFlow/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.monitor/-environment-subscription-monitor/event-flow.html +$dokka.location:it.unibo.alchemist.boundary.graphql.monitor/EnvironmentSubscriptionMonitor/finished/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.monitor/-environment-subscription-monitor/finished.html +$dokka.location:it.unibo.alchemist.boundary.graphql.monitor/EnvironmentSubscriptionMonitor/initialized/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.monitor/-environment-subscription-monitor/initialized.html +$dokka.location:it.unibo.alchemist.boundary.graphql.monitor/EnvironmentSubscriptionMonitor/stepDone/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Actionable[TypeParam(bounds=[kotlin.Any?])]?#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.monitor/-environment-subscription-monitor/step-done.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates////PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates//toGraphQLConcentrationSurrogate/it.unibo.alchemist.model.Concentration[TypeParam(bounds=[kotlin.Any])]#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/to-graph-q-l-concentration-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates//toGraphQLEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/to-graph-q-l-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates//toGraphQLLayerSurrogate/it.unibo.alchemist.model.Layer[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[kotlin.collections.List[kotlin.Number],TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/to-graph-q-l-layer-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates//toGraphQLMoleculeSurrogate/it.unibo.alchemist.model.Molecule#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/to-graph-q-l-molecule-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates//toGraphQLNeighborhoodSurrogate/it.unibo.alchemist.model.Neighborhood[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/to-graph-q-l-neighborhood-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates//toGraphQLNodeSurrogate/it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/to-graph-q-l-node-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates//toGraphQLReactionSurrogate/it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/to-graph-q-l-reaction-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates//toGraphQLSimulationSurrogate/it.unibo.alchemist.core.Simulation[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/to-graph-q-l-simulation-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates//toGraphQLTimeSurrogate/it.unibo.alchemist.model.Time#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/to-graph-q-l-time-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/ConcentrationSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-concentration-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/ConcentrationSurrogate/ConcentrationSurrogate/#it.unibo.alchemist.model.Concentration[TypeParam(bounds=[kotlin.Any?])]#kotlin.String/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-concentration-surrogate/-concentration-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/ConcentrationSurrogate/content/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-concentration-surrogate/content.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/ConcentrationSurrogate/origin/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-concentration-surrogate/origin.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate/EnvironmentSurrogate/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate/cloneNode/#kotlin.Int#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.PositionInput#kotlin.Double/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/clone-node.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate/dimensions/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate/getLayer/#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.MoleculeInput/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/get-layer.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate/getNeighborhood/#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/get-neighborhood.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate/layers/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/layers.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate/nodeById/#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/node-by-id.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate/nodeToPos/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/node-to-pos.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate/nodes/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/nodes.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/EnvironmentSurrogate/origin/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-environment-surrogate/origin.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/GenericPositionSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-generic-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/GenericPositionSurrogate/GenericPositionSurrogate/#kotlin.collections.List[kotlin.Double]#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-generic-position-surrogate/-generic-position-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/GenericPositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-generic-position-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/GenericPositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-generic-position-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/GraphQLSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-graph-q-l-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/GraphQLSurrogate/GraphQLSurrogate/#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-graph-q-l-surrogate/-graph-q-l-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/GraphQLSurrogate/origin/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-graph-q-l-surrogate/origin.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/LayerSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-layer-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/LayerSurrogate/LayerSurrogate/#it.unibo.alchemist.model.Layer[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[kotlin.collections.List[kotlin.Number],TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-layer-surrogate/-layer-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/LayerSurrogate/getValue/#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.PositionInput/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-layer-surrogate/get-value.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/LayerSurrogate/origin/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-layer-surrogate/origin.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/LayerSurrogate/posMapping/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-layer-surrogate/pos-mapping.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/MoleculeInput///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-molecule-input/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/MoleculeInput/MoleculeInput/#kotlin.String/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-molecule-input/-molecule-input.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/MoleculeInput/name/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-molecule-input/name.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/MoleculeSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-molecule-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/MoleculeSurrogate/MoleculeSurrogate/#it.unibo.alchemist.model.Molecule#kotlin.String/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-molecule-surrogate/-molecule-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/MoleculeSurrogate/name/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-molecule-surrogate/name.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/MoleculeSurrogate/origin/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-molecule-surrogate/origin.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NeighborhoodSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-neighborhood-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NeighborhoodSurrogate/NeighborhoodSurrogate/#it.unibo.alchemist.model.Neighborhood[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-neighborhood-surrogate/-neighborhood-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NeighborhoodSurrogate/contains/#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.NodeSurrogate[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-neighborhood-surrogate/contains.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NeighborhoodSurrogate/getCenter/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-neighborhood-surrogate/get-center.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NeighborhoodSurrogate/getNeighbors/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-neighborhood-surrogate/get-neighbors.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NeighborhoodSurrogate/isEmpty/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-neighborhood-surrogate/is-empty.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NeighborhoodSurrogate/origin/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-neighborhood-surrogate/origin.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NeighborhoodSurrogate/size/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-neighborhood-surrogate/size.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NodeSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-node-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NodeSurrogate/NodeSurrogate/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-node-surrogate/-node-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NodeSurrogate/contains/#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.MoleculeInput/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-node-surrogate/contains.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NodeSurrogate/contents/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-node-surrogate/contents.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NodeSurrogate/getConcentration/#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.MoleculeInput/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-node-surrogate/get-concentration.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NodeSurrogate/id/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-node-surrogate/id.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NodeSurrogate/moleculeCount/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-node-surrogate/molecule-count.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NodeSurrogate/origin/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-node-surrogate/origin.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NodeSurrogate/properties/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-node-surrogate/properties.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/NodeSurrogate/reactions/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-node-surrogate/reactions.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/Position2DSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position2-d-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/Position2DSurrogate/Position2DSurrogate/#kotlin.Double#kotlin.Double#kotlin.collections.List[kotlin.Double]#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position2-d-surrogate/-position2-d-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/Position2DSurrogate/coordinates/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position2-d-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/Position2DSurrogate/dimensions/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position2-d-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/Position2DSurrogate/x/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position2-d-surrogate/x.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/Position2DSurrogate/y/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position2-d-surrogate/y.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/PositionInput///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position-input/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/PositionInput/PositionInput/#kotlin.collections.List[kotlin.Double]#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position-input/-position-input.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/PositionInput/coordinates/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position-input/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/PositionInput/dimensions/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position-input/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/PositionSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/PositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/PositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/PositionSurrogate/toInputPosition/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-position-surrogate/to-input-position.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/ReactionSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-reaction-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/ReactionSurrogate/ReactionSurrogate/#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Context#it.unibo.alchemist.model.Context#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.NodeSurrogate[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-reaction-surrogate/-reaction-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/ReactionSurrogate/inputContext/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-reaction-surrogate/input-context.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/ReactionSurrogate/node/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-reaction-surrogate/node.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/ReactionSurrogate/origin/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-reaction-surrogate/origin.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/ReactionSurrogate/outputContext/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-reaction-surrogate/output-context.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/SimulationSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-simulation-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/SimulationSurrogate/SimulationSurrogate/#it.unibo.alchemist.core.Simulation[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-simulation-surrogate/-simulation-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/SimulationSurrogate/environment/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-simulation-surrogate/environment.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/SimulationSurrogate/origin/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-simulation-surrogate/origin.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/SimulationSurrogate/status/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-simulation-surrogate/status.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/SimulationSurrogate/time/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-simulation-surrogate/time.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/TimeSurrogate///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-time-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/TimeSurrogate/TimeSurrogate/#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-time-surrogate/-time-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/TimeSurrogate/doubleTime/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-time-surrogate/double-time.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.model.surrogates/TimeSurrogate/origin/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.model.surrogates/-time-surrogate/origin.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.mutations////PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.mutations/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.mutations/SimulationControl///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.mutations/-simulation-control/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.mutations/SimulationControl/SimulationControl/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.mutations/-simulation-control/-simulation-control.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.mutations/SimulationControl/pause/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.mutations/-simulation-control/pause.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.mutations/SimulationControl/play/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.mutations/-simulation-control/play.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.mutations/SimulationControl/terminate/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.mutations/-simulation-control/terminate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.queries////PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.queries/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.queries/EnvironmentQueries///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.queries/-environment-queries/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.queries/EnvironmentQueries/EnvironmentQueries/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.queries/-environment-queries/-environment-queries.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.queries/EnvironmentQueries/environment/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.queries/-environment-queries/environment.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.queries/EnvironmentQueries/simulation/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.queries/-environment-queries/simulation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.queries/NodeQueries///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.queries/-node-queries/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.queries/NodeQueries/NodeQueries/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.queries/-node-queries/-node-queries.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.queries/NodeQueries/neighborhood/#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.queries/-node-queries/neighborhood.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.queries/NodeQueries/nodePosition/#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.queries/-node-queries/node-position.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions////PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/EnvironmentSubscriptions///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/-environment-subscriptions/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/EnvironmentSubscriptions/EnvironmentSubscriptions/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/-environment-subscriptions/-environment-subscriptions.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/EnvironmentSubscriptions/environment/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/-environment-subscriptions/environment.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/EnvironmentSubscriptions/simulation/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/-environment-subscriptions/simulation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/NodeSubscriptions///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/-node-subscriptions/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/NodeSubscriptions/NodeSubscriptions/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/-node-subscriptions/-node-subscriptions.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/NodeSubscriptions/neighborhood/#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/-node-subscriptions/neighborhood.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/NodeSubscriptions/node/#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions/-node-subscriptions/node.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util////PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util//encodeConcentrationContentToString/#TypeParam(bounds=[kotlin.Any])?/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/encode-concentration-content-to-string.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util//encodeConcentrationContentToString/#it.unibo.alchemist.model.Concentration[TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/encode-concentration-content-to-string.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util//toMoleculeToConcentrationMap/kotlin.collections.Map[it.unibo.alchemist.model.Molecule,TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/to-molecule-to-concentration-map.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util//toNodeToPosMap/kotlin.collections.Map[kotlin.Int,TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/to-node-to-pos-map.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/GraphQLMap///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-graph-q-l-map/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/GraphQLMap/GraphQLMap/#kotlin.collections.Map[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any?])]#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-graph-q-l-map/-graph-q-l-map.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/GraphQLMap/get/#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-graph-q-l-map/get.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/GraphQLMap/originMap/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-graph-q-l-map/origin-map.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/GraphQLMap/size/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-graph-q-l-map/size.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/MoleculeToConcentrationEntry///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-molecule-to-concentration-entry/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/MoleculeToConcentrationEntry/MoleculeToConcentrationEntry/#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.MoleculeSurrogate#kotlin.String/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-molecule-to-concentration-entry/-molecule-to-concentration-entry.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/MoleculeToConcentrationEntry/concentration/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-molecule-to-concentration-entry/concentration.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/MoleculeToConcentrationEntry/molecule/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-molecule-to-concentration-entry/molecule.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/MoleculeToConcentrationMap///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-molecule-to-concentration-map/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/MoleculeToConcentrationMap/MoleculeToConcentrationMap/#kotlin.collections.Map[it.unibo.alchemist.boundary.graphql.schema.model.surrogates.MoleculeSurrogate,kotlin.String]#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-molecule-to-concentration-map/-molecule-to-concentration-map.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/MoleculeToConcentrationMap/entries/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-molecule-to-concentration-map/entries.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/MoleculeToConcentrationMap/get/#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.MoleculeInput/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-molecule-to-concentration-map/get.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/MoleculeToConcentrationMap/originMap/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-molecule-to-concentration-map/origin-map.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/MoleculeToConcentrationMap/size/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-molecule-to-concentration-map/size.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/NodeToPosEntry///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-node-to-pos-entry/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/NodeToPosEntry/NodeToPosEntry/#kotlin.Int#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.PositionSurrogate/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-node-to-pos-entry/-node-to-pos-entry.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/NodeToPosEntry/id/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-node-to-pos-entry/id.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/NodeToPosEntry/position/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-node-to-pos-entry/position.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/NodeToPosMap///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-node-to-pos-map/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/NodeToPosMap/NodeToPosMap/#kotlin.collections.Map[kotlin.Int,it.unibo.alchemist.boundary.graphql.schema.model.surrogates.PositionSurrogate]#kotlin.Int/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-node-to-pos-map/-node-to-pos-map.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/NodeToPosMap/entries/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-node-to-pos-map/entries.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/NodeToPosMap/originMap/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-node-to-pos-map/origin-map.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/NodeToPosMap/size/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-node-to-pos-map/size.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/PositionSurrogateUtils///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-position-surrogate-utils/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/PositionSurrogateUtils/fromPositionInput/#it.unibo.alchemist.boundary.graphql.schema.model.surrogates.PositionInput/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-position-surrogate-utils/from-position-input.html +$dokka.location:it.unibo.alchemist.boundary.graphql.schema.util/PositionSurrogateUtils/toPositionSurrogate/#it.unibo.alchemist.model.Position[*]/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql.schema.util/-position-surrogate-utils/to-position-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql////PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql/AlchemistSchemaGeneratorHooksProvider///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql/-alchemist-schema-generator-hooks-provider/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql/AlchemistSchemaGeneratorHooksProvider/AlchemistSchemaGeneratorHooksProvider/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql/-alchemist-schema-generator-hooks-provider/-alchemist-schema-generator-hooks-provider.html +$dokka.location:it.unibo.alchemist.boundary.graphql/AlchemistSchemaGeneratorHooksProvider/hooks/#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.boundary.graphql/-alchemist-schema-generator-hooks-provider/hooks.html +$dokka.location:it.unibo.alchemist.model.util////PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.model.util/index.html +$dokka.location:it.unibo.alchemist.model.util/Environments///PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.model.util/-environments/index.html +$dokka.location:it.unibo.alchemist.model.util/Environments/subscriptionMonitor/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#/PointingToDeclaration/alchemist-graphql-surrogates/it.unibo.alchemist.model.util/-environments/subscription-monitor.html +it.unibo.alchemist.boundary.graphql +it.unibo.alchemist.boundary.graphql.monitor +it.unibo.alchemist.boundary.graphql.schema.model.surrogates +it.unibo.alchemist.boundary.graphql.schema.operations.mutations +it.unibo.alchemist.boundary.graphql.schema.operations.queries +it.unibo.alchemist.boundary.graphql.schema.operations.subscriptions +it.unibo.alchemist.boundary.graphql.schema.util +it.unibo.alchemist.model.util From da1f7f36c0e5bf41ed41e977984be82d3de92ec8 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 17:59:12 +0000 Subject: [PATCH 078/196] chore(build): update the javadoc.io cache --- .../java-quadtree/1.0.2.list | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 dokka-cache/org.danilopianini/java-quadtree/1.0.2.list diff --git a/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list b/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list deleted file mode 100644 index a9c06fdff1..0000000000 --- a/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list +++ /dev/null @@ -1,25 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:org.danilopianini.util////PointingToDeclaration/java-quadtree/org.danilopianini.util/index.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree.Companion///PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-companion/index.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree.Companion/DEFAULT_CAPACITY/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-companion/-d-e-f-a-u-l-t_-c-a-p-a-c-i-t-y.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree///PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/index.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/FlexibleQuadTree/#kotlin.Int/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-flexible-quad-tree.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/dimensions/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/dimensions.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/insert.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/insert.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/maxElementsNumber/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/max-elements-number.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/move.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/move.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/query/#kotlin.Array[kotlin.DoubleArray]/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/query.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/query/#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/query.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/remove.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/remove.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/toString/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/to-string.html -$dokka.location:org.danilopianini.util/SpatialIndex///PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/index.html -$dokka.location:org.danilopianini.util/SpatialIndex/dimensions/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/dimensions.html -$dokka.location:org.danilopianini.util/SpatialIndex/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/insert.html -$dokka.location:org.danilopianini.util/SpatialIndex/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/move.html -$dokka.location:org.danilopianini.util/SpatialIndex/query/#kotlin.Array[kotlin.DoubleArray]/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/query.html -$dokka.location:org.danilopianini.util/SpatialIndex/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/remove.html -org.danilopianini.util From 78017adeb2e2c4d0332a7f83cf33c20d24058af6 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 18:19:42 +0000 Subject: [PATCH 079/196] chore(build): update the javadoc.io cache --- .../io.ktor/ktor-serialization/3.3.3.list | 29 ------------------- .../java-quadtree/1.0.2.list | 25 ++++++++++++++++ 2 files changed, 25 insertions(+), 29 deletions(-) delete mode 100644 dokka-cache/io.ktor/ktor-serialization/3.3.3.list create mode 100644 dokka-cache/org.danilopianini/java-quadtree/1.0.2.list diff --git a/dokka-cache/io.ktor/ktor-serialization/3.3.3.list b/dokka-cache/io.ktor/ktor-serialization/3.3.3.list deleted file mode 100644 index ad32c88a95..0000000000 --- a/dokka-cache/io.ktor/ktor-serialization/3.3.3.list +++ /dev/null @@ -1,29 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:io.ktor.serialization////PointingToDeclaration/ktor-serialization/io.ktor.serialization/index.html -$dokka.location:io.ktor.serialization//deserialize/io.ktor.serialization.WebsocketContentConverter#io.ktor.websocket.Frame#io.ktor.utils.io.charsets.Charset/PointingToDeclaration/ktor-serialization/io.ktor.serialization/deserialize.html -$dokka.location:io.ktor.serialization//deserialize/kotlin.collections.List[io.ktor.serialization.ContentConverter]#io.ktor.utils.io.ByteReadChannel#io.ktor.util.reflect.TypeInfo#io.ktor.utils.io.charsets.Charset/PointingToDeclaration/ktor-serialization/io.ktor.serialization/deserialize.html -$dokka.location:io.ktor.serialization//serialize/io.ktor.serialization.WebsocketContentConverter#TypeParam(bounds=[kotlin.Any?])#io.ktor.utils.io.charsets.Charset/PointingToDeclaration/ktor-serialization/io.ktor.serialization/serialize.html -$dokka.location:io.ktor.serialization//suitableCharset/io.ktor.http.Headers#io.ktor.utils.io.charsets.Charset/PointingToDeclaration/ktor-serialization/io.ktor.serialization/suitable-charset.html -$dokka.location:io.ktor.serialization//suitableCharsetOrNull/io.ktor.http.Headers#io.ktor.utils.io.charsets.Charset/PointingToDeclaration/ktor-serialization/io.ktor.serialization/suitable-charset-or-null.html -$dokka.location:io.ktor.serialization/Configuration///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-configuration/index.html -$dokka.location:io.ktor.serialization/Configuration/register/#io.ktor.http.ContentType#TypeParam(bounds=[io.ktor.serialization.ContentConverter])#kotlin.Function1[TypeParam(bounds=[io.ktor.serialization.ContentConverter]),kotlin.Unit]/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-configuration/register.html -$dokka.location:io.ktor.serialization/ContentConvertException///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-content-convert-exception/index.html -$dokka.location:io.ktor.serialization/ContentConvertException/ContentConvertException/#kotlin.String#kotlin.Throwable?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-content-convert-exception/-content-convert-exception.html -$dokka.location:io.ktor.serialization/ContentConverter///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-content-converter/index.html -$dokka.location:io.ktor.serialization/ContentConverter/deserialize/#io.ktor.utils.io.charsets.Charset#io.ktor.util.reflect.TypeInfo#io.ktor.utils.io.ByteReadChannel/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-content-converter/deserialize.html -$dokka.location:io.ktor.serialization/ContentConverter/serialize/#io.ktor.http.ContentType#io.ktor.utils.io.charsets.Charset#io.ktor.util.reflect.TypeInfo#kotlin.Any?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-content-converter/serialize.html -$dokka.location:io.ktor.serialization/JsonConvertException///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-json-convert-exception/index.html -$dokka.location:io.ktor.serialization/JsonConvertException/JsonConvertException/#kotlin.String#kotlin.Throwable?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-json-convert-exception/-json-convert-exception.html -$dokka.location:io.ktor.serialization/WebsocketContentConvertException///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-convert-exception/index.html -$dokka.location:io.ktor.serialization/WebsocketContentConvertException/WebsocketContentConvertException/#kotlin.String#kotlin.Throwable?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-convert-exception/-websocket-content-convert-exception.html -$dokka.location:io.ktor.serialization/WebsocketContentConverter///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-converter/index.html -$dokka.location:io.ktor.serialization/WebsocketContentConverter/deserialize/#io.ktor.utils.io.charsets.Charset#io.ktor.util.reflect.TypeInfo#io.ktor.websocket.Frame/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-converter/deserialize.html -$dokka.location:io.ktor.serialization/WebsocketContentConverter/isApplicable/#io.ktor.websocket.Frame/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-converter/is-applicable.html -$dokka.location:io.ktor.serialization/WebsocketContentConverter/serialize/#io.ktor.utils.io.charsets.Charset#io.ktor.util.reflect.TypeInfo#kotlin.Any?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-converter/serialize.html -$dokka.location:io.ktor.serialization/WebsocketConverterNotFoundException///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-converter-not-found-exception/index.html -$dokka.location:io.ktor.serialization/WebsocketConverterNotFoundException/WebsocketConverterNotFoundException/#kotlin.String#kotlin.Throwable?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-converter-not-found-exception/-websocket-converter-not-found-exception.html -$dokka.location:io.ktor.serialization/WebsocketDeserializeException///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-deserialize-exception/index.html -$dokka.location:io.ktor.serialization/WebsocketDeserializeException/WebsocketDeserializeException/#kotlin.String#kotlin.Throwable?#io.ktor.websocket.Frame/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-deserialize-exception/-websocket-deserialize-exception.html -$dokka.location:io.ktor.serialization/WebsocketDeserializeException/frame/#/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-deserialize-exception/frame.html -io.ktor.serialization diff --git a/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list b/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list new file mode 100644 index 0000000000..a9c06fdff1 --- /dev/null +++ b/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list @@ -0,0 +1,25 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:org.danilopianini.util////PointingToDeclaration/java-quadtree/org.danilopianini.util/index.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree.Companion///PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-companion/index.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree.Companion/DEFAULT_CAPACITY/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-companion/-d-e-f-a-u-l-t_-c-a-p-a-c-i-t-y.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree///PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/index.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/FlexibleQuadTree/#kotlin.Int/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-flexible-quad-tree.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/dimensions/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/dimensions.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/insert.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/insert.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/maxElementsNumber/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/max-elements-number.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/move.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/move.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/query/#kotlin.Array[kotlin.DoubleArray]/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/query.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/query/#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/query.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/remove.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/remove.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/toString/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/to-string.html +$dokka.location:org.danilopianini.util/SpatialIndex///PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/index.html +$dokka.location:org.danilopianini.util/SpatialIndex/dimensions/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/dimensions.html +$dokka.location:org.danilopianini.util/SpatialIndex/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/insert.html +$dokka.location:org.danilopianini.util/SpatialIndex/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/move.html +$dokka.location:org.danilopianini.util/SpatialIndex/query/#kotlin.Array[kotlin.DoubleArray]/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/query.html +$dokka.location:org.danilopianini.util/SpatialIndex/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/remove.html +org.danilopianini.util From 4ff63a309b43a2ee24ab88a3c173e89893d5ed8a Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 18:47:30 +0000 Subject: [PATCH 080/196] chore(build): update the javadoc.io cache --- .../io.ktor/ktor-serialization/3.3.3.list | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 dokka-cache/io.ktor/ktor-serialization/3.3.3.list diff --git a/dokka-cache/io.ktor/ktor-serialization/3.3.3.list b/dokka-cache/io.ktor/ktor-serialization/3.3.3.list new file mode 100644 index 0000000000..ad32c88a95 --- /dev/null +++ b/dokka-cache/io.ktor/ktor-serialization/3.3.3.list @@ -0,0 +1,29 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:io.ktor.serialization////PointingToDeclaration/ktor-serialization/io.ktor.serialization/index.html +$dokka.location:io.ktor.serialization//deserialize/io.ktor.serialization.WebsocketContentConverter#io.ktor.websocket.Frame#io.ktor.utils.io.charsets.Charset/PointingToDeclaration/ktor-serialization/io.ktor.serialization/deserialize.html +$dokka.location:io.ktor.serialization//deserialize/kotlin.collections.List[io.ktor.serialization.ContentConverter]#io.ktor.utils.io.ByteReadChannel#io.ktor.util.reflect.TypeInfo#io.ktor.utils.io.charsets.Charset/PointingToDeclaration/ktor-serialization/io.ktor.serialization/deserialize.html +$dokka.location:io.ktor.serialization//serialize/io.ktor.serialization.WebsocketContentConverter#TypeParam(bounds=[kotlin.Any?])#io.ktor.utils.io.charsets.Charset/PointingToDeclaration/ktor-serialization/io.ktor.serialization/serialize.html +$dokka.location:io.ktor.serialization//suitableCharset/io.ktor.http.Headers#io.ktor.utils.io.charsets.Charset/PointingToDeclaration/ktor-serialization/io.ktor.serialization/suitable-charset.html +$dokka.location:io.ktor.serialization//suitableCharsetOrNull/io.ktor.http.Headers#io.ktor.utils.io.charsets.Charset/PointingToDeclaration/ktor-serialization/io.ktor.serialization/suitable-charset-or-null.html +$dokka.location:io.ktor.serialization/Configuration///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-configuration/index.html +$dokka.location:io.ktor.serialization/Configuration/register/#io.ktor.http.ContentType#TypeParam(bounds=[io.ktor.serialization.ContentConverter])#kotlin.Function1[TypeParam(bounds=[io.ktor.serialization.ContentConverter]),kotlin.Unit]/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-configuration/register.html +$dokka.location:io.ktor.serialization/ContentConvertException///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-content-convert-exception/index.html +$dokka.location:io.ktor.serialization/ContentConvertException/ContentConvertException/#kotlin.String#kotlin.Throwable?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-content-convert-exception/-content-convert-exception.html +$dokka.location:io.ktor.serialization/ContentConverter///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-content-converter/index.html +$dokka.location:io.ktor.serialization/ContentConverter/deserialize/#io.ktor.utils.io.charsets.Charset#io.ktor.util.reflect.TypeInfo#io.ktor.utils.io.ByteReadChannel/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-content-converter/deserialize.html +$dokka.location:io.ktor.serialization/ContentConverter/serialize/#io.ktor.http.ContentType#io.ktor.utils.io.charsets.Charset#io.ktor.util.reflect.TypeInfo#kotlin.Any?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-content-converter/serialize.html +$dokka.location:io.ktor.serialization/JsonConvertException///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-json-convert-exception/index.html +$dokka.location:io.ktor.serialization/JsonConvertException/JsonConvertException/#kotlin.String#kotlin.Throwable?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-json-convert-exception/-json-convert-exception.html +$dokka.location:io.ktor.serialization/WebsocketContentConvertException///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-convert-exception/index.html +$dokka.location:io.ktor.serialization/WebsocketContentConvertException/WebsocketContentConvertException/#kotlin.String#kotlin.Throwable?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-convert-exception/-websocket-content-convert-exception.html +$dokka.location:io.ktor.serialization/WebsocketContentConverter///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-converter/index.html +$dokka.location:io.ktor.serialization/WebsocketContentConverter/deserialize/#io.ktor.utils.io.charsets.Charset#io.ktor.util.reflect.TypeInfo#io.ktor.websocket.Frame/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-converter/deserialize.html +$dokka.location:io.ktor.serialization/WebsocketContentConverter/isApplicable/#io.ktor.websocket.Frame/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-converter/is-applicable.html +$dokka.location:io.ktor.serialization/WebsocketContentConverter/serialize/#io.ktor.utils.io.charsets.Charset#io.ktor.util.reflect.TypeInfo#kotlin.Any?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-content-converter/serialize.html +$dokka.location:io.ktor.serialization/WebsocketConverterNotFoundException///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-converter-not-found-exception/index.html +$dokka.location:io.ktor.serialization/WebsocketConverterNotFoundException/WebsocketConverterNotFoundException/#kotlin.String#kotlin.Throwable?/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-converter-not-found-exception/-websocket-converter-not-found-exception.html +$dokka.location:io.ktor.serialization/WebsocketDeserializeException///PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-deserialize-exception/index.html +$dokka.location:io.ktor.serialization/WebsocketDeserializeException/WebsocketDeserializeException/#kotlin.String#kotlin.Throwable?#io.ktor.websocket.Frame/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-deserialize-exception/-websocket-deserialize-exception.html +$dokka.location:io.ktor.serialization/WebsocketDeserializeException/frame/#/PointingToDeclaration/ktor-serialization/io.ktor.serialization/-websocket-deserialize-exception/frame.html +io.ktor.serialization From 6ab908c443fb5981dcbf1402676d1f7591d46c05 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 19:11:40 +0000 Subject: [PATCH 081/196] chore(build): update the javadoc.io cache --- .../alchemist-graphql/42.3.18.list | 335 ++++++++++++++++++ .../alchemist-web-renderer/42.3.18.list | 282 --------------- .../java-quadtree/1.0.2.list | 25 -- .../org.danilopianini/listset/0.3.9.list | 1 - .../protelis-interpreter/18.5.0.list | 10 + 5 files changed, 345 insertions(+), 308 deletions(-) create mode 100644 dokka-cache/it.unibo.alchemist/alchemist-graphql/42.3.18.list delete mode 100644 dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list delete mode 100644 dokka-cache/org.danilopianini/java-quadtree/1.0.2.list delete mode 100644 dokka-cache/org.danilopianini/listset/0.3.9.list create mode 100644 dokka-cache/org.protelis/protelis-interpreter/18.5.0.list diff --git a/dokka-cache/it.unibo.alchemist/alchemist-graphql/42.3.18.list b/dokka-cache/it.unibo.alchemist/alchemist-graphql/42.3.18.list new file mode 100644 index 0000000000..0b99953f2f --- /dev/null +++ b/dokka-cache/it.unibo.alchemist/alchemist-graphql/42.3.18.list @@ -0,0 +1,335 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter////PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Data/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-data/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Data/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-data/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Data/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.ConcentrationSubscription.Data/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-data/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Environment///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-environment/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Environment/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-environment/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Environment/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-environment/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Environment/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.ConcentrationSubscription.Environment/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-environment/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Node///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-node/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Node/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-node/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Node/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-node/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Node/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.ConcentrationSubscription.Node/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-node/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Simulation///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-simulation/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Simulation/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-simulation/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Simulation/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-simulation/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter.Simulation/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.ConcentrationSubscription.Simulation/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/-simulation/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_ResponseAdapter///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-response-adapter/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_VariablesAdapter///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-variables-adapter/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/ConcentrationSubscription_VariablesAdapter/serializeVariables/#com.apollographql.apollo3.api.json.JsonWriter#it.unibo.alchemist.boundary.graphql.client.ConcentrationSubscription#com.apollographql.apollo3.api.CustomScalarAdapters#kotlin.Boolean/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-concentration-subscription_-variables-adapter/serialize-variables.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Contents///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-contents/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Contents/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-contents/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Contents/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-contents/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Contents/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Contents/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-contents/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Data/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-data/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Data/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-data/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Data/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Data/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-data/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Entry///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-entry/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Entry/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-entry/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Entry/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-entry/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Entry/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Entry/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-entry/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Environment///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-environment/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Environment/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-environment/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Environment/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-environment/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Environment/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Environment/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-environment/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Molecule///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-molecule/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Molecule/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-molecule/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Molecule/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-molecule/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Molecule/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Molecule/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-molecule/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Node///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-node/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Node/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-node/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Node/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-node/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Node/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Node/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-node/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Simulation///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-simulation/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Simulation/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-simulation/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Simulation/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-simulation/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter.Simulation/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Simulation/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/-simulation/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/NodesSubscription_ResponseAdapter///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-nodes-subscription_-response-adapter/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/PauseSimulationMutation_ResponseAdapter.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-pause-simulation-mutation_-response-adapter/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/PauseSimulationMutation_ResponseAdapter.Data/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-pause-simulation-mutation_-response-adapter/-data/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/PauseSimulationMutation_ResponseAdapter.Data/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-pause-simulation-mutation_-response-adapter/-data/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/PauseSimulationMutation_ResponseAdapter.Data/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.PauseSimulationMutation.Data/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-pause-simulation-mutation_-response-adapter/-data/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/PauseSimulationMutation_ResponseAdapter///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-pause-simulation-mutation_-response-adapter/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/PlaySimulationMutation_ResponseAdapter.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-play-simulation-mutation_-response-adapter/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/PlaySimulationMutation_ResponseAdapter.Data/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-play-simulation-mutation_-response-adapter/-data/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/PlaySimulationMutation_ResponseAdapter.Data/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-play-simulation-mutation_-response-adapter/-data/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/PlaySimulationMutation_ResponseAdapter.Data/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.PlaySimulationMutation.Data/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-play-simulation-mutation_-response-adapter/-data/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/PlaySimulationMutation_ResponseAdapter///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-play-simulation-mutation_-response-adapter/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/SimulationStatusQuery_ResponseAdapter.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-simulation-status-query_-response-adapter/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/SimulationStatusQuery_ResponseAdapter.Data/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-simulation-status-query_-response-adapter/-data/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/SimulationStatusQuery_ResponseAdapter.Data/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-simulation-status-query_-response-adapter/-data/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/SimulationStatusQuery_ResponseAdapter.Data/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.SimulationStatusQuery.Data/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-simulation-status-query_-response-adapter/-data/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/SimulationStatusQuery_ResponseAdapter.Simulation///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-simulation-status-query_-response-adapter/-simulation/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/SimulationStatusQuery_ResponseAdapter.Simulation/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-simulation-status-query_-response-adapter/-simulation/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/SimulationStatusQuery_ResponseAdapter.Simulation/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-simulation-status-query_-response-adapter/-simulation/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/SimulationStatusQuery_ResponseAdapter.Simulation/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.SimulationStatusQuery.Simulation/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-simulation-status-query_-response-adapter/-simulation/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/SimulationStatusQuery_ResponseAdapter///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-simulation-status-query_-response-adapter/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/TerminateSimulationMutation_ResponseAdapter.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-terminate-simulation-mutation_-response-adapter/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/TerminateSimulationMutation_ResponseAdapter.Data/RESPONSE_NAMES/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-terminate-simulation-mutation_-response-adapter/-data/-r-e-s-p-o-n-s-e_-n-a-m-e-s.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/TerminateSimulationMutation_ResponseAdapter.Data/fromJson/#com.apollographql.apollo3.api.json.JsonReader#com.apollographql.apollo3.api.CustomScalarAdapters/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-terminate-simulation-mutation_-response-adapter/-data/from-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/TerminateSimulationMutation_ResponseAdapter.Data/toJson/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#it.unibo.alchemist.boundary.graphql.client.TerminateSimulationMutation.Data/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-terminate-simulation-mutation_-response-adapter/-data/to-json.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.adapter/TerminateSimulationMutation_ResponseAdapter///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.adapter/-terminate-simulation-mutation_-response-adapter/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections////PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/ConcentrationSubscriptionSelections///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-concentration-subscription-selections/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/ConcentrationSubscriptionSelections/__root/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-concentration-subscription-selections/__root.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/NodesSubscriptionSelections///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-nodes-subscription-selections/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/NodesSubscriptionSelections/__root/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-nodes-subscription-selections/__root.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/PauseSimulationMutationSelections///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-pause-simulation-mutation-selections/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/PauseSimulationMutationSelections/__root/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-pause-simulation-mutation-selections/__root.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/PlaySimulationMutationSelections///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-play-simulation-mutation-selections/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/PlaySimulationMutationSelections/__root/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-play-simulation-mutation-selections/__root.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/SimulationStatusQuerySelections///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-simulation-status-query-selections/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/SimulationStatusQuerySelections/__root/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-simulation-status-query-selections/__root.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/TerminateSimulationMutationSelections///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-terminate-simulation-mutation-selections/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.selections/TerminateSimulationMutationSelections/__root/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.selections/-terminate-simulation-mutation-selections/__root.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type////PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/EnvironmentSurrogate.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-environment-surrogate/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/EnvironmentSurrogate.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-environment-surrogate/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/EnvironmentSurrogate///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-environment-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/EnvironmentSurrogate/EnvironmentSurrogate/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-environment-surrogate/-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLBoolean.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-boolean/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLBoolean.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-boolean/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLBoolean///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-boolean/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLBoolean/GraphQLBoolean/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-boolean/-graph-q-l-boolean.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLFloat.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-float/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLFloat.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-float/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLFloat///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-float/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLFloat/GraphQLFloat/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-float/-graph-q-l-float.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLID.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-i-d/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLID.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-i-d/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLID///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-i-d/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLID/GraphQLID/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-i-d/-graph-q-l-i-d.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLInt.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-int/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLInt.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-int/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLInt///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-int/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLInt/GraphQLInt/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-int/-graph-q-l-int.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLString.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-string/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLString.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-string/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLString///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-string/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/GraphQLString/GraphQLString/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-graph-q-l-string/-graph-q-l-string.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeSurrogate.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-surrogate/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeSurrogate.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-surrogate/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeSurrogate///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeSurrogate/MoleculeSurrogate/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-surrogate/-molecule-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeToConcentrationEntry.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-to-concentration-entry/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeToConcentrationEntry.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-to-concentration-entry/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeToConcentrationEntry///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-to-concentration-entry/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeToConcentrationEntry/MoleculeToConcentrationEntry/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-to-concentration-entry/-molecule-to-concentration-entry.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeToConcentrationMap.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-to-concentration-map/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeToConcentrationMap.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-to-concentration-map/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeToConcentrationMap///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-to-concentration-map/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/MoleculeToConcentrationMap/MoleculeToConcentrationMap/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-molecule-to-concentration-map/-molecule-to-concentration-map.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Mutation.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-mutation/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Mutation.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-mutation/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Mutation///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-mutation/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Mutation/Mutation/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-mutation/-mutation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/NodeSurrogate.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-node-surrogate/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/NodeSurrogate.Companion/__getConcentration_molecule/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-node-surrogate/-companion/__get-concentration_molecule.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/NodeSurrogate.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-node-surrogate/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/NodeSurrogate///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-node-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/NodeSurrogate/NodeSurrogate/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-node-surrogate/-node-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Query.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-query/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Query.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-query/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Query///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-query/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Query/Query/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-query/-query.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/SimulationSurrogate.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-simulation-surrogate/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/SimulationSurrogate.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-simulation-surrogate/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/SimulationSurrogate///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-simulation-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/SimulationSurrogate/SimulationSurrogate/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-simulation-surrogate/-simulation-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Subscription.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-subscription/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Subscription.Companion/type/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-subscription/-companion/type.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Subscription///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-subscription/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client.type/Subscription/Subscription/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client.type/-subscription/-subscription.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client////PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Companion/OPERATION_DOCUMENT/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-companion/-o-p-e-r-a-t-i-o-n_-d-o-c-u-m-e-n-t.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Companion/OPERATION_ID/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-companion/-o-p-e-r-a-t-i-o-n_-i-d.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Companion/OPERATION_NAME/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-companion/-o-p-e-r-a-t-i-o-n_-n-a-m-e.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Data/Data/#it.unibo.alchemist.boundary.graphql.client.ConcentrationSubscription.Simulation/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-data/-data.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Data/simulation/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-data/simulation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Environment///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-environment/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Environment/Environment/#kotlin.collections.List[it.unibo.alchemist.boundary.graphql.client.ConcentrationSubscription.Node]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-environment/-environment.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Environment/nodes/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-environment/nodes.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Node///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-node/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Node/Node/#kotlin.String?/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-node/-node.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Node/getConcentration/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-node/get-concentration.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Simulation///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-simulation/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Simulation/Simulation/#kotlin.Double#it.unibo.alchemist.boundary.graphql.client.ConcentrationSubscription.Environment/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-simulation/-simulation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Simulation/environment/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-simulation/environment.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription.Simulation/time/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-simulation/time.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription/ConcentrationSubscription/#kotlin.String/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/-concentration-subscription.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription/adapter/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/adapter.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription/document/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/document.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription/id/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/id.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription/ignoreErrors/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/ignore-errors.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription/moleculeName/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/molecule-name.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription/name/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/name.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription/rootField/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/root-field.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/ConcentrationSubscription/serializeVariables/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#kotlin.Boolean/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-concentration-subscription/serialize-variables.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/DefaultGraphQLClient///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-default-graph-q-l-client/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/DefaultGraphQLClient/DefaultGraphQLClient/#kotlin.String#kotlin.Int#kotlin.Boolean/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-default-graph-q-l-client/-default-graph-q-l-client.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/DefaultGraphQLClient/close/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-default-graph-q-l-client/close.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/DefaultGraphQLClient/host/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-default-graph-q-l-client/host.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/DefaultGraphQLClient/mutation/#com.apollographql.apollo3.api.Mutation[TypeParam(bounds=[com.apollographql.apollo3.api.Mutation.Data])]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-default-graph-q-l-client/mutation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/DefaultGraphQLClient/port/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-default-graph-q-l-client/port.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/DefaultGraphQLClient/query/#com.apollographql.apollo3.api.Query[TypeParam(bounds=[com.apollographql.apollo3.api.Query.Data])]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-default-graph-q-l-client/query.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/DefaultGraphQLClient/subscription/#com.apollographql.apollo3.api.Subscription[TypeParam(bounds=[com.apollographql.apollo3.api.Subscription.Data])]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-default-graph-q-l-client/subscription.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/DefaultGraphQLClient/subscriptionUrl/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-default-graph-q-l-client/subscription-url.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClient///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClient/close/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client/close.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClient/host/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client/host.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClient/mutation/#com.apollographql.apollo3.api.Mutation[TypeParam(bounds=[com.apollographql.apollo3.api.Mutation.Data])]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client/mutation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClient/port/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client/port.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClient/query/#com.apollographql.apollo3.api.Query[TypeParam(bounds=[com.apollographql.apollo3.api.Query.Data])]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client/query.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClient/serverUrl/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client/server-url.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClient/subscription/#com.apollographql.apollo3.api.Subscription[TypeParam(bounds=[com.apollographql.apollo3.api.Subscription.Data])]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client/subscription.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClient/subscriptionUrl/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client/subscription-url.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClientFactory///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client-factory/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClientFactory/basicClient/#kotlin.String#kotlin.Int/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client-factory/basic-client.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/GraphQLClientFactory/subscriptionClient/#kotlin.String#kotlin.Int/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-graph-q-l-client-factory/subscription-client.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Companion/OPERATION_DOCUMENT/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-companion/-o-p-e-r-a-t-i-o-n_-d-o-c-u-m-e-n-t.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Companion/OPERATION_ID/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-companion/-o-p-e-r-a-t-i-o-n_-i-d.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Companion/OPERATION_NAME/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-companion/-o-p-e-r-a-t-i-o-n_-n-a-m-e.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Contents///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-contents/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Contents/Contents/#kotlin.collections.List[it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Entry]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-contents/-contents.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Contents/entries/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-contents/entries.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Data/Data/#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Simulation/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-data/-data.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Data/simulation/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-data/simulation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Entry///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-entry/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Entry/Entry/#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Molecule#kotlin.String/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-entry/-entry.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Entry/concentration/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-entry/concentration.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Entry/molecule/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-entry/molecule.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Environment///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-environment/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Environment/Environment/#kotlin.collections.List[it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Node]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-environment/-environment.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Environment/nodes/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-environment/nodes.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Molecule///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-molecule/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Molecule/Molecule/#kotlin.String/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-molecule/-molecule.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Molecule/name/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-molecule/name.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Node///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-node/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Node/Node/#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Contents/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-node/-node.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Node/contents/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-node/contents.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Simulation///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-simulation/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Simulation/Simulation/#kotlin.String#kotlin.Double#it.unibo.alchemist.boundary.graphql.client.NodesSubscription.Environment/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-simulation/-simulation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Simulation/environment/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-simulation/environment.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Simulation/status/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-simulation/status.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription.Simulation/time/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-simulation/time.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription/NodesSubscription/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/-nodes-subscription.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription/adapter/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/adapter.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription/document/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/document.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription/equals/#kotlin.Any?/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/equals.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription/hashCode/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/hash-code.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription/id/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/id.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription/ignoreErrors/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/ignore-errors.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription/name/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/name.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription/rootField/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/root-field.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/NodesSubscription/serializeVariables/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#kotlin.Boolean/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-nodes-subscription/serialize-variables.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation.Companion/OPERATION_DOCUMENT/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/-companion/-o-p-e-r-a-t-i-o-n_-d-o-c-u-m-e-n-t.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation.Companion/OPERATION_ID/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/-companion/-o-p-e-r-a-t-i-o-n_-i-d.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation.Companion/OPERATION_NAME/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/-companion/-o-p-e-r-a-t-i-o-n_-n-a-m-e.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation.Data/Data/#kotlin.String/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/-data/-data.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation.Data/pause/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/-data/pause.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation/PauseSimulationMutation/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/-pause-simulation-mutation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation/adapter/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/adapter.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation/document/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/document.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation/equals/#kotlin.Any?/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/equals.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation/hashCode/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/hash-code.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation/id/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/id.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation/ignoreErrors/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/ignore-errors.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation/name/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/name.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation/rootField/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/root-field.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PauseSimulationMutation/serializeVariables/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#kotlin.Boolean/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-pause-simulation-mutation/serialize-variables.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation.Companion/OPERATION_DOCUMENT/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/-companion/-o-p-e-r-a-t-i-o-n_-d-o-c-u-m-e-n-t.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation.Companion/OPERATION_ID/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/-companion/-o-p-e-r-a-t-i-o-n_-i-d.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation.Companion/OPERATION_NAME/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/-companion/-o-p-e-r-a-t-i-o-n_-n-a-m-e.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation.Data/Data/#kotlin.String/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/-data/-data.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation.Data/play/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/-data/play.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation/PlaySimulationMutation/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/-play-simulation-mutation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation/adapter/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/adapter.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation/document/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/document.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation/equals/#kotlin.Any?/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/equals.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation/hashCode/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/hash-code.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation/id/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/id.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation/ignoreErrors/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/ignore-errors.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation/name/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/name.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation/rootField/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/root-field.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/PlaySimulationMutation/serializeVariables/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#kotlin.Boolean/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-play-simulation-mutation/serialize-variables.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationHandler///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-handler/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationHandler/SimulationHandler/#it.unibo.alchemist.boundary.graphql.client.GraphQLClient/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-handler/-simulation-handler.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationHandler/pause/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-handler/pause.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationHandler/play/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-handler/play.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationHandler/status/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-handler/status.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationHandler/terminate/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-handler/terminate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery.Companion/OPERATION_DOCUMENT/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-companion/-o-p-e-r-a-t-i-o-n_-d-o-c-u-m-e-n-t.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery.Companion/OPERATION_ID/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-companion/-o-p-e-r-a-t-i-o-n_-i-d.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery.Companion/OPERATION_NAME/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-companion/-o-p-e-r-a-t-i-o-n_-n-a-m-e.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery.Data/Data/#it.unibo.alchemist.boundary.graphql.client.SimulationStatusQuery.Simulation/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-data/-data.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery.Data/simulation/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-data/simulation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery.Simulation///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-simulation/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery.Simulation/Simulation/#kotlin.String/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-simulation/-simulation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery.Simulation/status/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-simulation/status.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery/SimulationStatusQuery/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/-simulation-status-query.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery/adapter/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/adapter.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery/document/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/document.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery/equals/#kotlin.Any?/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/equals.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery/hashCode/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/hash-code.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery/id/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/id.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery/ignoreErrors/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/ignore-errors.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery/name/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/name.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery/rootField/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/root-field.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/SimulationStatusQuery/serializeVariables/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#kotlin.Boolean/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-simulation-status-query/serialize-variables.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation.Companion///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation.Companion/OPERATION_DOCUMENT/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/-companion/-o-p-e-r-a-t-i-o-n_-d-o-c-u-m-e-n-t.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation.Companion/OPERATION_ID/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/-companion/-o-p-e-r-a-t-i-o-n_-i-d.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation.Companion/OPERATION_NAME/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/-companion/-o-p-e-r-a-t-i-o-n_-n-a-m-e.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation.Data///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/-data/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation.Data/Data/#kotlin.String/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/-data/-data.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation.Data/terminate/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/-data/terminate.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation/TerminateSimulationMutation/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/-terminate-simulation-mutation.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation/adapter/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/adapter.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation/document/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/document.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation/equals/#kotlin.Any?/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/equals.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation/hashCode/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/hash-code.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation/id/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/id.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation/ignoreErrors/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/ignore-errors.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation/name/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/name.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation/rootField/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/root-field.html +$dokka.location:it.unibo.alchemist.boundary.graphql.client/TerminateSimulationMutation/serializeVariables/#com.apollographql.apollo3.api.json.JsonWriter#com.apollographql.apollo3.api.CustomScalarAdapters#kotlin.Boolean/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.client/-terminate-simulation-mutation/serialize-variables.html +$dokka.location:it.unibo.alchemist.boundary.graphql.server.modules////PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.server.modules/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.server.modules//graphQLModule/io.ktor.server.application.Application#it.unibo.alchemist.model.Environment[*,*]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.server.modules/graph-q-l-module.html +$dokka.location:it.unibo.alchemist.boundary.graphql.server.modules//graphQLRoutingModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.server.modules/graph-q-l-routing-module.html +$dokka.location:it.unibo.alchemist.boundary.graphql.utils////PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.utils/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.utils/DefaultGraphQLSettings///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.utils/-default-graph-q-l-settings/index.html +$dokka.location:it.unibo.alchemist.boundary.graphql.utils/DefaultGraphQLSettings/DEFAULT_HOST/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.utils/-default-graph-q-l-settings/-d-e-f-a-u-l-t_-h-o-s-t.html +$dokka.location:it.unibo.alchemist.boundary.graphql.utils/DefaultGraphQLSettings/DEFAULT_PORT/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.graphql.utils/-default-graph-q-l-settings/-d-e-f-a-u-l-t_-p-o-r-t.html +$dokka.location:it.unibo.alchemist.boundary.monitors////PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.monitors/index.html +$dokka.location:it.unibo.alchemist.boundary.monitors/GraphQLMonitor///PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.monitors/-graph-q-l-monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.monitors/GraphQLMonitor/GraphQLMonitor/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.String#kotlin.Int#kotlin.Boolean#kotlinx.coroutines.CoroutineDispatcher/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.monitors/-graph-q-l-monitor/-graph-q-l-monitor.html +$dokka.location:it.unibo.alchemist.boundary.monitors/GraphQLMonitor/environment/#/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.monitors/-graph-q-l-monitor/environment.html +$dokka.location:it.unibo.alchemist.boundary.monitors/GraphQLMonitor/finished/#it.unibo.alchemist.model.Environment[kotlin.Any,kotlin.Nothing]#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.monitors/-graph-q-l-monitor/finished.html +$dokka.location:it.unibo.alchemist.boundary.monitors/GraphQLMonitor/initialized/#it.unibo.alchemist.model.Environment[kotlin.Any,kotlin.Nothing]/PointingToDeclaration/alchemist-graphql/it.unibo.alchemist.boundary.monitors/-graph-q-l-monitor/initialized.html +it.unibo.alchemist.boundary.graphql.client +it.unibo.alchemist.boundary.graphql.client.adapter +it.unibo.alchemist.boundary.graphql.client.selections +it.unibo.alchemist.boundary.graphql.client.type +it.unibo.alchemist.boundary.graphql.server.modules +it.unibo.alchemist.boundary.graphql.utils +it.unibo.alchemist.boundary.monitors diff --git a/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list b/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list deleted file mode 100644 index 415747ae38..0000000000 --- a/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list +++ /dev/null @@ -1,282 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:it.unibo.alchemist.boundary.launchers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/index.html -$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/index.html -$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/WebRendererLauncher/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/-web-renderer-launcher.html -$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/launch/#it.unibo.alchemist.boundary.Loader/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/launch.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//Button/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButtonGroup/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/active/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/active.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/disabled/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/disabled.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/onClick/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/on-click.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/variant.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/defaultValue/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/default-value.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/name.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/onChange/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/on-change.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/size/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/size.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/type/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/type.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/id.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/value/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/value.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//Modal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalBody/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-body.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalFooter/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-footer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalHeader/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalTitle/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps/closeButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/close-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/onHide/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/on-hide.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/show/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/show.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps/className/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/class-name.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//Navbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//NavbarBrand/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-brand.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/bg/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/bg.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/variant.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/client/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/client.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/endpoint/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/endpoint.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentClient/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-client.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentServer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-server.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/getSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/get-simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/pauseSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/pause-simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/playSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/play-simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppContent/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-content.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppNavbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-navbar.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//PlayButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//RenderModeButtons/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-render-mode-buttons.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//WarningModal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps/status/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/message/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/message.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/title/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/title.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic//updateState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.client.logic.UpdateStateStrategy#it.unibo.alchemist.boundary.webui.client.logic.AutoRenderModeStrategy/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/update-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/invoke.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/HwAutoRenderModeStrategy/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/-hw-auto-render-mode-strategy.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/invoke.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/minHwConcurrency/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/min-hw-concurrency.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/RESTUpdateStateStrategy/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/-r-e-s-t-update-state-strategy.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/client-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/retrieve-simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/server-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/client-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/retrieve-simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/server-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/SetBitmap/#korlibs.image.bitmap.Bitmap?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/-set-bitmap.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/bitmap.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/SetPlayButton/#it.unibo.alchemist.boundary.webui.common.utility.Action/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/-set-play-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/action/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/action.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/SetRenderMode/#it.unibo.alchemist.boundary.webui.common.model.RenderMode/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/-set-render-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/render-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/SetStatusSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/-set-status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//bitmapReducer/#korlibs.image.bitmap.Bitmap?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/bitmap-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//playButtonReducer/#it.unibo.alchemist.boundary.webui.common.utility.Action#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/play-button-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//renderModeReducer/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/render-mode-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//statusSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/status-surrogate-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state//rootReducer/#it.unibo.alchemist.boundary.webui.client.state.ClientState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/root-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/ClientState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.common.utility.Action#korlibs.image.bitmap.Bitmap?#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/-client-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/bitmap.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/playButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/play-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/render-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/store.html -$dokka.location:it.unibo.alchemist.boundary.webui.client////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client//App/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/-app.html -$dokka.location:it.unibo.alchemist.boundary.webui.client//main/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/main.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//decodeEnvironmentSurrogate/kotlinx.serialization.json.Json#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/decode-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//encodeEnvironmentSurrogate/kotlinx.serialization.json.Json#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/encode-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//jsonFormat/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/json-format.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules/concentrationModule/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/concentration-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EmptyConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-empty-concentration-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/polymorphicSerializer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/polymorphic-serializer.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/uninitializedEnvironment/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/uninitialized-environment.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/EnvironmentSurrogate/#kotlin.Int#kotlin.collections.List[it.unibo.alchemist.boundary.webui.common.model.surrogate.NodeSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/nodes/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/nodes.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/GeneralPositionSurrogate/#kotlin.DoubleArray#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/-general-position-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/coordinates.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/equals/#kotlin.Any?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/equals.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/hashCode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/hash-code.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/MoleculeSurrogate/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/-molecule-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/name.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/descriptor.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/deserialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/serialize/#kotlinx.serialization.encoding.Encoder#it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/serialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/NodeSurrogate/#kotlin.Int#kotlin.collections.Map[it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate,TypeParam(bounds=[kotlin.Any])]#TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/-node-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/contents/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/contents.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/id.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/position/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/position.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/Position2DSurrogate/#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/-position2-d-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/coordinates.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/x/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/x.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/y/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/y.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/coordinates.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.INIT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-i-n-i-t/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.PAUSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-p-a-u-s-e-d/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.READY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-e-a-d-y/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.RUNNING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-u-n-n-i-n-g/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.TERMINATED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-t-e-r-m-i-n-a-t-e-d/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/entries.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/value-of.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/values.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.AUTO///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-a-u-t-o/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.CLIENT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-c-l-i-e-n-t/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.SERVER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-s-e-r-v-e-r/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/entries.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/value-of.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/values.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/descriptor.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/deserialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/serialize/#kotlinx.serialization.encoding.Encoder#korlibs.image.bitmap.Bitmap32/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/serialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/BitmapRenderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/-bitmap-renderer.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/render.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/render.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/CommonState/#it.unibo.alchemist.boundary.webui.common.renderer.Renderer[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate,korlibs.image.bitmap.Bitmap]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/-common-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/renderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/renderer.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PAUSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-a-u-s-e/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PLAY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-l-a-y/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/entries.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/value-of.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/values.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_CLIENT_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-c-l-i-e-n-t_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_SERVER_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-s-e-r-v-e-r_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PAUSE_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-a-u-s-e_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PLAY_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-l-a-y_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_STATUS_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-s-t-a-t-u-s_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//installModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/install-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//routingModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/routing-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//startBrowserModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/start-browser-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/EnvironmentMonitor/#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/-environment-monitor.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/finished/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/finished.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/initialized/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/initialized.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/stepDone/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Actionable[TypeParam(bounds=[kotlin.Any?])]?#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/step-done.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory/makeEnvironmentMonitor/#it.unibo.alchemist.model.Environment[*,*]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/make-environment-monitor.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes//mainRoute/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/main-route.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentClientMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-client-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentServerMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-server-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPause/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-pause.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPlay/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-play.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationStatus/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/SetEnvironmentSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/-set-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/SetSimulation/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/-set-simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//environmentSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/environment-surrogate-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//simulationReducer/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/simulation-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state//rootReducer/#it.unibo.alchemist.boundary.webui.server.state.ServerState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/root-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/ServerState/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/-server-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/store.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toMoleculeSurrogate/it.unibo.alchemist.model.Molecule#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-molecule-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toNodeSurrogate/it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-node-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toStatusSurrogate/it.unibo.alchemist.core.Status#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate/toEmptyConcentration/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/to-empty-concentration.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate/toSuitablePositionSurrogate/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/to-suitable-position-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion/respond/io.ktor.server.routing.RoutingContext#it.unibo.alchemist.boundary.webui.server.utility.Response[TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/respond.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/Response/#io.ktor.http.HttpStatusCode#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-response.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/code/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/code.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/content/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/content.html -it.unibo.alchemist.boundary.launchers -it.unibo.alchemist.boundary.webui.client -it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons -it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal -it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar -it.unibo.alchemist.boundary.webui.client.api -it.unibo.alchemist.boundary.webui.client.api.utility -it.unibo.alchemist.boundary.webui.client.components -it.unibo.alchemist.boundary.webui.client.logic -it.unibo.alchemist.boundary.webui.client.state -it.unibo.alchemist.boundary.webui.client.state.actions -it.unibo.alchemist.boundary.webui.client.state.reducers -it.unibo.alchemist.boundary.webui.common.model -it.unibo.alchemist.boundary.webui.common.model.serialization -it.unibo.alchemist.boundary.webui.common.model.surrogate -it.unibo.alchemist.boundary.webui.common.renderer -it.unibo.alchemist.boundary.webui.common.state -it.unibo.alchemist.boundary.webui.common.utility -it.unibo.alchemist.boundary.webui.server.modules -it.unibo.alchemist.boundary.webui.server.monitor -it.unibo.alchemist.boundary.webui.server.routes -it.unibo.alchemist.boundary.webui.server.state -it.unibo.alchemist.boundary.webui.server.state.actions -it.unibo.alchemist.boundary.webui.server.state.reducers -it.unibo.alchemist.boundary.webui.server.surrogates.utility -it.unibo.alchemist.boundary.webui.server.utility diff --git a/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list b/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list deleted file mode 100644 index a9c06fdff1..0000000000 --- a/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list +++ /dev/null @@ -1,25 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:org.danilopianini.util////PointingToDeclaration/java-quadtree/org.danilopianini.util/index.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree.Companion///PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-companion/index.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree.Companion/DEFAULT_CAPACITY/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-companion/-d-e-f-a-u-l-t_-c-a-p-a-c-i-t-y.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree///PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/index.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/FlexibleQuadTree/#kotlin.Int/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-flexible-quad-tree.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/dimensions/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/dimensions.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/insert.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/insert.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/maxElementsNumber/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/max-elements-number.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/move.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/move.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/query/#kotlin.Array[kotlin.DoubleArray]/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/query.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/query/#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/query.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/remove.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/remove.html -$dokka.location:org.danilopianini.util/FlexibleQuadTree/toString/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/to-string.html -$dokka.location:org.danilopianini.util/SpatialIndex///PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/index.html -$dokka.location:org.danilopianini.util/SpatialIndex/dimensions/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/dimensions.html -$dokka.location:org.danilopianini.util/SpatialIndex/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/insert.html -$dokka.location:org.danilopianini.util/SpatialIndex/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/move.html -$dokka.location:org.danilopianini.util/SpatialIndex/query/#kotlin.Array[kotlin.DoubleArray]/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/query.html -$dokka.location:org.danilopianini.util/SpatialIndex/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/remove.html -org.danilopianini.util diff --git a/dokka-cache/org.danilopianini/listset/0.3.9.list b/dokka-cache/org.danilopianini/listset/0.3.9.list deleted file mode 100644 index 9b56bbd751..0000000000 --- a/dokka-cache/org.danilopianini/listset/0.3.9.list +++ /dev/null @@ -1 +0,0 @@ -org.danilopianini.util diff --git a/dokka-cache/org.protelis/protelis-interpreter/18.5.0.list b/dokka-cache/org.protelis/protelis-interpreter/18.5.0.list new file mode 100644 index 0000000000..5d89e93987 --- /dev/null +++ b/dokka-cache/org.protelis/protelis-interpreter/18.5.0.list @@ -0,0 +1,10 @@ +org.protelis +org.protelis.lang +org.protelis.lang.datatype +org.protelis.lang.datatype.impl +org.protelis.lang.interpreter +org.protelis.lang.interpreter.impl +org.protelis.lang.interpreter.util +org.protelis.lang.loading +org.protelis.vm +org.protelis.vm.impl From 53b1f4613a8293a18d0bf7124989e097dced9981 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 19:38:17 +0000 Subject: [PATCH 082/196] chore(build): update the javadoc.io cache --- .../io.ktor/ktor-server-netty/3.3.3.list | 81 ----- .../alchemist-api/42.3.18.list | 287 ++++++++++++++++++ .../alchemist-web-renderer/42.3.18.list | 282 +++++++++++++++++ .../java-quadtree/1.0.2.list | 25 ++ .../org.danilopianini/listset/0.3.9.list | 1 + 5 files changed, 595 insertions(+), 81 deletions(-) delete mode 100644 dokka-cache/io.ktor/ktor-server-netty/3.3.3.list create mode 100644 dokka-cache/it.unibo.alchemist/alchemist-api/42.3.18.list create mode 100644 dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list create mode 100644 dokka-cache/org.danilopianini/java-quadtree/1.0.2.list create mode 100644 dokka-cache/org.danilopianini/listset/0.3.9.list diff --git a/dokka-cache/io.ktor/ktor-server-netty/3.3.3.list b/dokka-cache/io.ktor/ktor-server-netty/3.3.3.list deleted file mode 100644 index 697f5a7619..0000000000 --- a/dokka-cache/io.ktor/ktor-server-netty/3.3.3.list +++ /dev/null @@ -1,81 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:io.ktor.server.netty.cio////PointingToDeclaration/ktor-server-netty/io.ktor.server.netty.cio/index.html -$dokka.location:io.ktor.server.netty.cio/NettyResponsePipelineException///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty.cio/-netty-response-pipeline-exception/index.html -$dokka.location:io.ktor.server.netty.cio/NettyResponsePipelineException/NettyResponsePipelineException/#kotlin.String/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty.cio/-netty-response-pipeline-exception/-netty-response-pipeline-exception.html -$dokka.location:io.ktor.server.netty////PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/index.html -$dokka.location:io.ktor.server.netty//suspendAwait/io.netty.util.concurrent.Future[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/suspend-await.html -$dokka.location:io.ktor.server.netty//suspendAwait/io.netty.util.concurrent.Future[TypeParam(bounds=[kotlin.Any?])]#kotlin.Function2[kotlin.Throwable,kotlin.coroutines.Continuation[TypeParam(bounds=[kotlin.Any?])],kotlin.Unit]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/suspend-await.html -$dokka.location:io.ktor.server.netty//suspendWriteAwait/io.netty.util.concurrent.Future[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/suspend-write-await.html -$dokka.location:io.ktor.server.netty/EngineMain///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-engine-main/index.html -$dokka.location:io.ktor.server.netty/EngineMain/createServer/#kotlin.Array[kotlin.String]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-engine-main/create-server.html -$dokka.location:io.ktor.server.netty/EngineMain/main/#kotlin.Array[kotlin.String]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-engine-main/main.html -$dokka.location:io.ktor.server.netty/EventLoopGroupProxy.Companion///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/-companion/index.html -$dokka.location:io.ktor.server.netty/EventLoopGroupProxy.Companion/create/#kotlin.Int/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/-companion/create.html -$dokka.location:io.ktor.server.netty/EventLoopGroupProxy///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/index.html -$dokka.location:io.ktor.server.netty/EventLoopGroupProxy/EventLoopGroupProxy/#kotlin.reflect.KClass[io.netty.channel.socket.ServerSocketChannel]#io.netty.channel.EventLoopGroup/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/-event-loop-group-proxy.html -$dokka.location:io.ktor.server.netty/EventLoopGroupProxy/channel/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/channel.html -$dokka.location:io.ktor.server.netty/EventLoopGroupProxy/isShutdown/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/is-shutdown.html -$dokka.location:io.ktor.server.netty/EventLoopGroupProxy/isShuttingDown/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/is-shutting-down.html -$dokka.location:io.ktor.server.netty/EventLoopGroupProxy/isTerminated/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/is-terminated.html -$dokka.location:io.ktor.server.netty/Netty///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty/index.html -$dokka.location:io.ktor.server.netty/Netty/configuration/#kotlin.Function1[io.ktor.server.netty.NettyApplicationEngine.Configuration,kotlin.Unit]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty/configuration.html -$dokka.location:io.ktor.server.netty/Netty/create/#io.ktor.server.application.ApplicationEnvironment#io.ktor.events.Events#kotlin.Boolean#io.ktor.server.netty.NettyApplicationEngine.Configuration#kotlin.Function0[io.ktor.server.application.Application]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty/create.html -$dokka.location:io.ktor.server.netty/NettyApplicationCall///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/index.html -$dokka.location:io.ktor.server.netty/NettyApplicationCall/NettyApplicationCall/#io.ktor.server.application.Application#io.netty.channel.ChannelHandlerContext#kotlin.Any/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/-netty-application-call.html -$dokka.location:io.ktor.server.netty/NettyApplicationCall/context/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/context.html -$dokka.location:io.ktor.server.netty/NettyApplicationCall/request/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/request.html -$dokka.location:io.ktor.server.netty/NettyApplicationCall/response/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/response.html -$dokka.location:io.ktor.server.netty/NettyApplicationCall/responseWriteJob/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/response-write-job.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/index.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/Configuration/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/-configuration.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/channelPipelineConfig/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/channel-pipeline-config.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/configureBootstrap/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/configure-bootstrap.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/enableH2c/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/enable-h2c.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/enableHttp2/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/enable-http2.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/httpServerCodec/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/http-server-codec.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/maxChunkSize/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/max-chunk-size.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/maxHeaderSize/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/max-header-size.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/maxInitialLineLength/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/max-initial-line-length.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/requestReadTimeoutSeconds/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/request-read-timeout-seconds.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/responseWriteTimeoutSeconds/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/response-write-timeout-seconds.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/runningLimit/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/running-limit.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/shareWorkGroup/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/share-work-group.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/tcpKeepAlive/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/tcp-keep-alive.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/index.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine/NettyApplicationEngine/#io.ktor.server.application.ApplicationEnvironment#io.ktor.events.Events#kotlin.Boolean#io.ktor.server.netty.NettyApplicationEngine.Configuration#kotlin.Function0[io.ktor.server.application.Application]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-netty-application-engine.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine/configuration/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/configuration.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine/start/#kotlin.Boolean/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/start.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine/stop/#kotlin.Long#kotlin.Long/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/stop.html -$dokka.location:io.ktor.server.netty/NettyApplicationEngine/toString/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/to-string.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequest///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/index.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequest/NettyApplicationRequest/#io.ktor.server.application.PipelineCall#kotlin.coroutines.CoroutineContext#io.netty.channel.ChannelHandlerContext#io.ktor.utils.io.ByteReadChannel#kotlin.String#kotlin.Boolean/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/-netty-application-request.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequest/close/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/close.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequest/context/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/context.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequest/cookies/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/cookies.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequest/coroutineContext/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/coroutine-context.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequest/queryParameters/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/query-parameters.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequest/rawQueryParameters/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/raw-query-parameters.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/index.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/NettyApplicationRequestHeaders/#io.netty.handler.codec.http.HttpRequest/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/-netty-application-request-headers.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/caseInsensitiveName/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/case-insensitive-name.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/contains/#kotlin.String#kotlin.String/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/contains.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/contains/#kotlin.String/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/contains.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/entries/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/entries.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/forEach/#kotlin.Function2[kotlin.String,kotlin.collections.List[kotlin.String],kotlin.Unit]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/for-each.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/get/#kotlin.String/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/get.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/getAll/#kotlin.String/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/get-all.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/isEmpty/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/is-empty.html -$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/names/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/names.html -$dokka.location:io.ktor.server.netty/NettyApplicationResponse.Companion///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/-companion/index.html -$dokka.location:io.ktor.server.netty/NettyApplicationResponse.Companion/responseStatusCache/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/-companion/response-status-cache.html -$dokka.location:io.ktor.server.netty/NettyApplicationResponse///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/index.html -$dokka.location:io.ktor.server.netty/NettyApplicationResponse/NettyApplicationResponse/#io.ktor.server.netty.NettyApplicationCall#io.netty.channel.ChannelHandlerContext#kotlin.coroutines.CoroutineContext#kotlin.coroutines.CoroutineContext/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/-netty-application-response.html -$dokka.location:io.ktor.server.netty/NettyApplicationResponse/cancel/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/cancel.html -$dokka.location:io.ktor.server.netty/NettyApplicationResponse/responseMessage/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/response-message.html -$dokka.location:io.ktor.server.netty/NettyChannelInitializer.Companion///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-channel-initializer/-companion/index.html -$dokka.location:io.ktor.server.netty/NettyChannelInitializer///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-channel-initializer/index.html -$dokka.location:io.ktor.server.netty/NettyChannelInitializer/NettyChannelInitializer/#kotlin.Function0[io.ktor.server.application.Application]#io.ktor.server.engine.EnginePipeline#io.ktor.server.application.ApplicationEnvironment#io.netty.util.concurrent.EventExecutorGroup#kotlin.coroutines.CoroutineContext#kotlin.coroutines.CoroutineContext#io.ktor.server.engine.EngineConnectorConfig#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Function0[io.netty.handler.codec.http.HttpServerCodec]#kotlin.Function1[io.netty.channel.ChannelPipeline,kotlin.Unit]#kotlin.Boolean#kotlin.Boolean/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-channel-initializer/-netty-channel-initializer.html -$dokka.location:io.ktor.server.netty/NettyChannelInitializer/NettyChannelInitializer/#kotlin.Function0[io.ktor.server.application.Application]#io.ktor.server.engine.EnginePipeline#io.ktor.server.application.ApplicationEnvironment#io.netty.util.concurrent.EventExecutorGroup#kotlin.coroutines.CoroutineContext#kotlin.coroutines.CoroutineContext#io.ktor.server.engine.EngineConnectorConfig#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Function0[io.netty.handler.codec.http.HttpServerCodec]#kotlin.Function1[io.netty.channel.ChannelPipeline,kotlin.Unit]#kotlin.Boolean/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-channel-initializer/-netty-channel-initializer.html -io.ktor.server.netty -io.ktor.server.netty.cio diff --git a/dokka-cache/it.unibo.alchemist/alchemist-api/42.3.18.list b/dokka-cache/it.unibo.alchemist/alchemist-api/42.3.18.list new file mode 100644 index 0000000000..b08805adc4 --- /dev/null +++ b/dokka-cache/it.unibo.alchemist/alchemist-api/42.3.18.list @@ -0,0 +1,287 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:it.unibo.alchemist.boundary////PointingToDeclaration/alchemist-api/it.unibo.alchemist.boundary/index.html +$dokka.location:it.unibo.alchemist.boundary/OutputMonitor///PointingToDeclaration/alchemist-api/it.unibo.alchemist.boundary/-output-monitor/index.html +$dokka.location:it.unibo.alchemist.boundary/OutputMonitor/finished/#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Time#long/PointingToDeclaration/alchemist-api/it.unibo.alchemist.boundary/-output-monitor/finished.html +$dokka.location:it.unibo.alchemist.boundary/OutputMonitor/initialized/#it.unibo.alchemist.model.Environment/PointingToDeclaration/alchemist-api/it.unibo.alchemist.boundary/-output-monitor/initialized.html +$dokka.location:it.unibo.alchemist.boundary/OutputMonitor/stepDone/#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Actionable#it.unibo.alchemist.model.Time#long/PointingToDeclaration/alchemist-api/it.unibo.alchemist.boundary/-output-monitor/step-done.html +$dokka.location:it.unibo.alchemist.core////PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/index.html +$dokka.location:it.unibo.alchemist.core/DependencyGraph///PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-dependency-graph/index.html +$dokka.location:it.unibo.alchemist.core/DependencyGraph/addNeighbor/#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Node/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-dependency-graph/add-neighbor.html +$dokka.location:it.unibo.alchemist.core/DependencyGraph/createDependencies/#it.unibo.alchemist.model.Actionable/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-dependency-graph/create-dependencies.html +$dokka.location:it.unibo.alchemist.core/DependencyGraph/globalInputContextReactions/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-dependency-graph/global-input-context-reactions.html +$dokka.location:it.unibo.alchemist.core/DependencyGraph/outboundDependencies/#it.unibo.alchemist.model.Actionable/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-dependency-graph/outbound-dependencies.html +$dokka.location:it.unibo.alchemist.core/DependencyGraph/removeDependencies/#it.unibo.alchemist.model.Actionable/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-dependency-graph/remove-dependencies.html +$dokka.location:it.unibo.alchemist.core/DependencyGraph/removeNeighbor/#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Node/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-dependency-graph/remove-neighbor.html +$dokka.location:it.unibo.alchemist.core/Scheduler///PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-scheduler/index.html +$dokka.location:it.unibo.alchemist.core/Scheduler/addReaction/#it.unibo.alchemist.model.Actionable/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-scheduler/add-reaction.html +$dokka.location:it.unibo.alchemist.core/Scheduler/getNext/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-scheduler/get-next.html +$dokka.location:it.unibo.alchemist.core/Scheduler/removeReaction/#it.unibo.alchemist.model.Actionable/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-scheduler/remove-reaction.html +$dokka.location:it.unibo.alchemist.core/Scheduler/updateReaction/#it.unibo.alchemist.model.Actionable/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-scheduler/update-reaction.html +$dokka.location:it.unibo.alchemist.core/Simulation///PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/index.html +$dokka.location:it.unibo.alchemist.core/Simulation/addOutputMonitor/#it.unibo.alchemist.boundary.OutputMonitor/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/add-output-monitor.html +$dokka.location:it.unibo.alchemist.core/Simulation/getEnvironment/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/get-environment.html +$dokka.location:it.unibo.alchemist.core/Simulation/getError/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/get-error.html +$dokka.location:it.unibo.alchemist.core/Simulation/getOutputMonitors/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/get-output-monitors.html +$dokka.location:it.unibo.alchemist.core/Simulation/getStatus/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/get-status.html +$dokka.location:it.unibo.alchemist.core/Simulation/getStep/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/get-step.html +$dokka.location:it.unibo.alchemist.core/Simulation/getTime/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/get-time.html +$dokka.location:it.unibo.alchemist.core/Simulation/goToStep/#long/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/go-to-step.html +$dokka.location:it.unibo.alchemist.core/Simulation/goToTime/#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/go-to-time.html +$dokka.location:it.unibo.alchemist.core/Simulation/neighborAdded/#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Node/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/neighbor-added.html +$dokka.location:it.unibo.alchemist.core/Simulation/neighborRemoved/#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Node/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/neighbor-removed.html +$dokka.location:it.unibo.alchemist.core/Simulation/nodeAdded/#it.unibo.alchemist.model.Node/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/node-added.html +$dokka.location:it.unibo.alchemist.core/Simulation/nodeMoved/#it.unibo.alchemist.model.Node/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/node-moved.html +$dokka.location:it.unibo.alchemist.core/Simulation/nodeRemoved/#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Neighborhood/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/node-removed.html +$dokka.location:it.unibo.alchemist.core/Simulation/pause/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/pause.html +$dokka.location:it.unibo.alchemist.core/Simulation/play/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/play.html +$dokka.location:it.unibo.alchemist.core/Simulation/reactionAdded/#it.unibo.alchemist.model.Actionable/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/reaction-added.html +$dokka.location:it.unibo.alchemist.core/Simulation/reactionRemoved/#it.unibo.alchemist.model.Actionable/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/reaction-removed.html +$dokka.location:it.unibo.alchemist.core/Simulation/removeOutputMonitor/#it.unibo.alchemist.boundary.OutputMonitor/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/remove-output-monitor.html +$dokka.location:it.unibo.alchemist.core/Simulation/schedule/#org.jooq.lambda.fi.lang.CheckedRunnable/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/schedule.html +$dokka.location:it.unibo.alchemist.core/Simulation/terminate/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/terminate.html +$dokka.location:it.unibo.alchemist.core/Simulation/waitFor/#it.unibo.alchemist.core.Status#long#java.util.concurrent.TimeUnit/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-simulation/wait-for.html +$dokka.location:it.unibo.alchemist.core/Status.INIT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-api/it.unibo.alchemist.core/-status/-i-n-i-t/index.html +$dokka.location:it.unibo.alchemist.core/Status.PAUSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-api/it.unibo.alchemist.core/-status/-p-a-u-s-e-d/index.html +$dokka.location:it.unibo.alchemist.core/Status.READY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-api/it.unibo.alchemist.core/-status/-r-e-a-d-y/index.html +$dokka.location:it.unibo.alchemist.core/Status.RUNNING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-api/it.unibo.alchemist.core/-status/-r-u-n-n-i-n-g/index.html +$dokka.location:it.unibo.alchemist.core/Status.TERMINATED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-api/it.unibo.alchemist.core/-status/-t-e-r-m-i-n-a-t-e-d/index.html +$dokka.location:it.unibo.alchemist.core/Status///PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-status/index.html +$dokka.location:it.unibo.alchemist.core/Status/isReachableFrom/#it.unibo.alchemist.core.Status/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-status/is-reachable-from.html +$dokka.location:it.unibo.alchemist.core/Status/valueOf/#java.lang.String/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-status/value-of.html +$dokka.location:it.unibo.alchemist.core/Status/values/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.core/-status/values.html +$dokka.location:it.unibo.alchemist.model.geometry////PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/index.html +$dokka.location:it.unibo.alchemist.model.geometry/Shape///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-shape/index.html +$dokka.location:it.unibo.alchemist.model.geometry/Shape/centroid/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-shape/centroid.html +$dokka.location:it.unibo.alchemist.model.geometry/Shape/contains/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-shape/contains.html +$dokka.location:it.unibo.alchemist.model.geometry/Shape/diameter/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-shape/diameter.html +$dokka.location:it.unibo.alchemist.model.geometry/Shape/intersects/#it.unibo.alchemist.model.geometry.Shape[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]]),TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^^]])]])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-shape/intersects.html +$dokka.location:it.unibo.alchemist.model.geometry/Shape/radius/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-shape/radius.html +$dokka.location:it.unibo.alchemist.model.geometry/Shape/transformed/#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Transformation[TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^^]])]]),kotlin.Unit]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-shape/transformed.html +$dokka.location:it.unibo.alchemist.model.geometry/Transformation///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-transformation/index.html +$dokka.location:it.unibo.alchemist.model.geometry/Transformation/origin/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-transformation/origin.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/index.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/angleBetween/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/angle-between.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/coerceAtLeast/#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/coerce-at-least.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/coerceAtMost/#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/coerce-at-most.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/coerceIn/#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/coerce-in.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/coordinates/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/coordinates.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/dimensions/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/dimensions.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/distanceTo/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/distance-to.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/div/#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/div.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/dot/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/dot.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/fromCoordinates/#kotlin.DoubleArray/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/from-coordinates.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/get/#kotlin.Int/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/get.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/magnitude/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/magnitude.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/minus/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/minus.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/normal/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/normal.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/normalized/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/normalized.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/plus/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/plus.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/resized/#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/resized.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/times/#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/times.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector/zero/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector/zero.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D.Companion///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/-companion/index.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D.Companion/zCross/#it.unibo.alchemist.model.geometry.Vector2D[*]#it.unibo.alchemist.model.geometry.Vector2D[*]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/-companion/z-cross.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/index.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/asAngle/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/as-angle.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/component1/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/component1.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/component2/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/component2.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/dot/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector2D[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/dot.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/isInRectangle/#it.unibo.alchemist.model.geometry.Vector2D[*]#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/is-in-rectangle.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/minus/#kotlin.Pair[kotlin.Double,kotlin.Double]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/minus.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/newFrom/#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/new-from.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/normalized/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/normalized.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/plus/#kotlin.Pair[kotlin.Double,kotlin.Double]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/plus.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/surrounding/#kotlin.Double#kotlin.Int/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/surrounding.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/surroundingPointAt/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector2D[^]])#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/surrounding-point-at.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/surroundingPointAt/#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/surrounding-point-at.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/x/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/x.html +$dokka.location:it.unibo.alchemist.model.geometry/Vector2D/y/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model.geometry/-vector2-d/y.html +$dokka.location:it.unibo.alchemist.model////PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/index.html +$dokka.location:it.unibo.alchemist.model/Action///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-action/index.html +$dokka.location:it.unibo.alchemist.model/Action/cloneAction/#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Reaction/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-action/clone-action.html +$dokka.location:it.unibo.alchemist.model/Action/execute/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-action/execute.html +$dokka.location:it.unibo.alchemist.model/Action/getContext/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-action/get-context.html +$dokka.location:it.unibo.alchemist.model/Action/getOutboundDependencies/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-action/get-outbound-dependencies.html +$dokka.location:it.unibo.alchemist.model/Actionable///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/index.html +$dokka.location:it.unibo.alchemist.model/Actionable/actions/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/actions.html +$dokka.location:it.unibo.alchemist.model/Actionable/canExecute/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/can-execute.html +$dokka.location:it.unibo.alchemist.model/Actionable/conditions/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/conditions.html +$dokka.location:it.unibo.alchemist.model/Actionable/execute/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/execute.html +$dokka.location:it.unibo.alchemist.model/Actionable/inboundDependencies/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/inbound-dependencies.html +$dokka.location:it.unibo.alchemist.model/Actionable/initializationComplete/#it.unibo.alchemist.model.Time#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),*]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/initialization-complete.html +$dokka.location:it.unibo.alchemist.model/Actionable/outboundDependencies/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/outbound-dependencies.html +$dokka.location:it.unibo.alchemist.model/Actionable/rate/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/rate.html +$dokka.location:it.unibo.alchemist.model/Actionable/tau/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/tau.html +$dokka.location:it.unibo.alchemist.model/Actionable/timeDistribution/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/time-distribution.html +$dokka.location:it.unibo.alchemist.model/Actionable/update/#it.unibo.alchemist.model.Time#kotlin.Boolean#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),*]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-actionable/update.html +$dokka.location:it.unibo.alchemist.model/BenchmarkableEnvironment///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-benchmarkable-environment/index.html +$dokka.location:it.unibo.alchemist.model/BenchmarkableEnvironment/enableBenchmark/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-benchmarkable-environment/enable-benchmark.html +$dokka.location:it.unibo.alchemist.model/BenchmarkableEnvironment/getBenchmarkResult/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-benchmarkable-environment/get-benchmark-result.html +$dokka.location:it.unibo.alchemist.model/Concentration///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-concentration/index.html +$dokka.location:it.unibo.alchemist.model/Concentration/getContent/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-concentration/get-content.html +$dokka.location:it.unibo.alchemist.model/Condition///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-condition/index.html +$dokka.location:it.unibo.alchemist.model/Condition/cloneCondition/#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Reaction/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-condition/clone-condition.html +$dokka.location:it.unibo.alchemist.model/Condition/getContext/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-condition/get-context.html +$dokka.location:it.unibo.alchemist.model/Condition/getInboundDependencies/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-condition/get-inbound-dependencies.html +$dokka.location:it.unibo.alchemist.model/Condition/getNode/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-condition/get-node.html +$dokka.location:it.unibo.alchemist.model/Condition/getPropensityContribution/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-condition/get-propensity-contribution.html +$dokka.location:it.unibo.alchemist.model/Condition/isValid/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-condition/is-valid.html +$dokka.location:it.unibo.alchemist.model/Condition/reactionReady/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-condition/reaction-ready.html +$dokka.location:it.unibo.alchemist.model/Context.GLOBAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-api/it.unibo.alchemist.model/-context/-g-l-o-b-a-l/index.html +$dokka.location:it.unibo.alchemist.model/Context.LOCAL///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-api/it.unibo.alchemist.model/-context/-l-o-c-a-l/index.html +$dokka.location:it.unibo.alchemist.model/Context.NEIGHBORHOOD///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-api/it.unibo.alchemist.model/-context/-n-e-i-g-h-b-o-r-h-o-o-d/index.html +$dokka.location:it.unibo.alchemist.model/Context///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-context/index.html +$dokka.location:it.unibo.alchemist.model/Context/getWider/#it.unibo.alchemist.model.Context#it.unibo.alchemist.model.Context/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-context/get-wider.html +$dokka.location:it.unibo.alchemist.model/Context/valueOf/#java.lang.String/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-context/value-of.html +$dokka.location:it.unibo.alchemist.model/Context/values/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-context/values.html +$dokka.location:it.unibo.alchemist.model/Dependency///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-dependency/index.html +$dokka.location:it.unibo.alchemist.model/Dependency/EVERYTHING/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-dependency/-e-v-e-r-y-t-h-i-n-g.html +$dokka.location:it.unibo.alchemist.model/Dependency/EVERY_MOLECULE/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-dependency/-e-v-e-r-y_-m-o-l-e-c-u-l-e.html +$dokka.location:it.unibo.alchemist.model/Dependency/MOVEMENT/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-dependency/-m-o-v-e-m-e-n-t.html +$dokka.location:it.unibo.alchemist.model/Dependency/dependsOn/#it.unibo.alchemist.model.Dependency/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-dependency/depends-on.html +$dokka.location:it.unibo.alchemist.model/Dependency/makesDependent/#it.unibo.alchemist.model.Dependency/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-dependency/makes-dependent.html +$dokka.location:it.unibo.alchemist.model/Environment///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/index.html +$dokka.location:it.unibo.alchemist.model/Environment/addGlobalReaction/#it.unibo.alchemist.model.GlobalReaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/add-global-reaction.html +$dokka.location:it.unibo.alchemist.model/Environment/addLayer/#it.unibo.alchemist.model.Molecule#it.unibo.alchemist.model.Layer[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/add-layer.html +$dokka.location:it.unibo.alchemist.model/Environment/addNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/add-node.html +$dokka.location:it.unibo.alchemist.model/Environment/addTerminator/#it.unibo.alchemist.model.TerminationPredicate[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/add-terminator.html +$dokka.location:it.unibo.alchemist.model/Environment/addTerminator/#kotlin.Function1[it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])],kotlin.Boolean]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/add-terminator.html +$dokka.location:it.unibo.alchemist.model/Environment/dimensions/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/dimensions.html +$dokka.location:it.unibo.alchemist.model/Environment/getDistanceBetweenNodes/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/get-distance-between-nodes.html +$dokka.location:it.unibo.alchemist.model/Environment/getLayer/#it.unibo.alchemist.model.Molecule/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/get-layer.html +$dokka.location:it.unibo.alchemist.model/Environment/getNeighborhood/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/get-neighborhood.html +$dokka.location:it.unibo.alchemist.model/Environment/getNodeByID/#kotlin.Int/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/get-node-by-i-d.html +$dokka.location:it.unibo.alchemist.model/Environment/getNodesWithinRange/#TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/get-nodes-within-range.html +$dokka.location:it.unibo.alchemist.model/Environment/getNodesWithinRange/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/get-nodes-within-range.html +$dokka.location:it.unibo.alchemist.model/Environment/getPosition/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/get-position.html +$dokka.location:it.unibo.alchemist.model/Environment/globalReactions/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/global-reactions.html +$dokka.location:it.unibo.alchemist.model/Environment/incarnation/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/incarnation.html +$dokka.location:it.unibo.alchemist.model/Environment/isTerminated/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/is-terminated.html +$dokka.location:it.unibo.alchemist.model/Environment/layers/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/layers.html +$dokka.location:it.unibo.alchemist.model/Environment/linkingRule/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/linking-rule.html +$dokka.location:it.unibo.alchemist.model/Environment/makePosition/#kotlin.DoubleArray/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/make-position.html +$dokka.location:it.unibo.alchemist.model/Environment/makePosition/#kotlin.Number/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/make-position.html +$dokka.location:it.unibo.alchemist.model/Environment/makePosition/#kotlin.collections.List[kotlin.Number]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/make-position.html +$dokka.location:it.unibo.alchemist.model/Environment/moveNodeToPosition/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/move-node-to-position.html +$dokka.location:it.unibo.alchemist.model/Environment/nodeCount/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/node-count.html +$dokka.location:it.unibo.alchemist.model/Environment/nodes/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/nodes.html +$dokka.location:it.unibo.alchemist.model/Environment/offset/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/offset.html +$dokka.location:it.unibo.alchemist.model/Environment/removeGlobalReaction/#it.unibo.alchemist.model.GlobalReaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/remove-global-reaction.html +$dokka.location:it.unibo.alchemist.model/Environment/removeNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/remove-node.html +$dokka.location:it.unibo.alchemist.model/Environment/simulation/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/simulation.html +$dokka.location:it.unibo.alchemist.model/Environment/simulationOrNull/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/simulation-or-null.html +$dokka.location:it.unibo.alchemist.model/Environment/size/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/size.html +$dokka.location:it.unibo.alchemist.model/Environment/sizeInDistanceUnits/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment/size-in-distance-units.html +$dokka.location:it.unibo.alchemist.model/EnvironmentWithObstacles///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment-with-obstacles/index.html +$dokka.location:it.unibo.alchemist.model/EnvironmentWithObstacles/addObstacle/#TypeParam(bounds=[it.unibo.alchemist.model.Obstacle[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]])]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment-with-obstacles/add-obstacle.html +$dokka.location:it.unibo.alchemist.model/EnvironmentWithObstacles/intersectsObstacle/#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment-with-obstacles/intersects-obstacle.html +$dokka.location:it.unibo.alchemist.model/EnvironmentWithObstacles/next/#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment-with-obstacles/next.html +$dokka.location:it.unibo.alchemist.model/EnvironmentWithObstacles/obstacles/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment-with-obstacles/obstacles.html +$dokka.location:it.unibo.alchemist.model/EnvironmentWithObstacles/removeObstacle/#TypeParam(bounds=[it.unibo.alchemist.model.Obstacle[TypeParam(bounds=[it.unibo.alchemist.model.Position[^^], it.unibo.alchemist.model.geometry.Vector[^^]])]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-environment-with-obstacles/remove-obstacle.html +$dokka.location:it.unibo.alchemist.model/EuclideanEnvironment///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-euclidean-environment/index.html +$dokka.location:it.unibo.alchemist.model/EuclideanEnvironment/moveNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#TypeParam(bounds=[it.unibo.alchemist.model.Position[^], it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-euclidean-environment/move-node.html +$dokka.location:it.unibo.alchemist.model/EuclideanEnvironment/origin/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-euclidean-environment/origin.html +$dokka.location:it.unibo.alchemist.model/GeoPosition///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-geo-position/index.html +$dokka.location:it.unibo.alchemist.model/GeoPosition/getCoordinate/#int/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-geo-position/get-coordinate.html +$dokka.location:it.unibo.alchemist.model/GeoPosition/getLatitude/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-geo-position/get-latitude.html +$dokka.location:it.unibo.alchemist.model/GeoPosition/getLongitude/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-geo-position/get-longitude.html +$dokka.location:it.unibo.alchemist.model/GeoPosition/minus/#it.unibo.alchemist.model.GeoPosition/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-geo-position/minus.html +$dokka.location:it.unibo.alchemist.model/GeoPosition/plus/#it.unibo.alchemist.model.GeoPosition/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-geo-position/plus.html +$dokka.location:it.unibo.alchemist.model/GlobalReaction///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-global-reaction/index.html +$dokka.location:it.unibo.alchemist.model/Incarnation///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-incarnation/index.html +$dokka.location:it.unibo.alchemist.model/Incarnation/createAction/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.TimeDistribution#it.unibo.alchemist.model.Actionable#java.lang.Object/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-incarnation/create-action.html +$dokka.location:it.unibo.alchemist.model/Incarnation/createConcentration/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-incarnation/create-concentration.html +$dokka.location:it.unibo.alchemist.model/Incarnation/createConcentration/#java.lang.Object/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-incarnation/create-concentration.html +$dokka.location:it.unibo.alchemist.model/Incarnation/createCondition/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.TimeDistribution#it.unibo.alchemist.model.Actionable#java.lang.Object/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-incarnation/create-condition.html +$dokka.location:it.unibo.alchemist.model/Incarnation/createMolecule/#java.lang.String/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-incarnation/create-molecule.html +$dokka.location:it.unibo.alchemist.model/Incarnation/createNode/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Environment#java.lang.Object/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-incarnation/create-node.html +$dokka.location:it.unibo.alchemist.model/Incarnation/createReaction/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.TimeDistribution#java.lang.Object/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-incarnation/create-reaction.html +$dokka.location:it.unibo.alchemist.model/Incarnation/createTimeDistribution/#org.apache.commons.math3.random.RandomGenerator#it.unibo.alchemist.model.Environment#it.unibo.alchemist.model.Node#java.lang.Object/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-incarnation/create-time-distribution.html +$dokka.location:it.unibo.alchemist.model/Incarnation/getProperty/#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Molecule#java.lang.String/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-incarnation/get-property.html +$dokka.location:it.unibo.alchemist.model/Layer///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-layer/index.html +$dokka.location:it.unibo.alchemist.model/Layer/getValue/#P/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-layer/get-value.html +$dokka.location:it.unibo.alchemist.model/LinkingRule///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-linking-rule/index.html +$dokka.location:it.unibo.alchemist.model/LinkingRule/computeNeighborhood/#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Environment/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-linking-rule/compute-neighborhood.html +$dokka.location:it.unibo.alchemist.model/LinkingRule/isLocallyConsistent/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-linking-rule/is-locally-consistent.html +$dokka.location:it.unibo.alchemist.model/Molecule///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-molecule/index.html +$dokka.location:it.unibo.alchemist.model/Molecule/getName/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-molecule/get-name.html +$dokka.location:it.unibo.alchemist.model/Neighborhood///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-neighborhood/index.html +$dokka.location:it.unibo.alchemist.model/Neighborhood/add/#it.unibo.alchemist.model.Node/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-neighborhood/add.html +$dokka.location:it.unibo.alchemist.model/Neighborhood/contains/#it.unibo.alchemist.model.Node/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-neighborhood/contains.html +$dokka.location:it.unibo.alchemist.model/Neighborhood/getCenter/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-neighborhood/get-center.html +$dokka.location:it.unibo.alchemist.model/Neighborhood/getNeighbors/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-neighborhood/get-neighbors.html +$dokka.location:it.unibo.alchemist.model/Neighborhood/isEmpty/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-neighborhood/is-empty.html +$dokka.location:it.unibo.alchemist.model/Neighborhood/remove/#it.unibo.alchemist.model.Node/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-neighborhood/remove.html +$dokka.location:it.unibo.alchemist.model/Neighborhood/size/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-neighborhood/size.html +$dokka.location:it.unibo.alchemist.model/Node.Companion///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/-companion/index.html +$dokka.location:it.unibo.alchemist.model/Node.Companion/asProperty/it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/-companion/as-property.html +$dokka.location:it.unibo.alchemist.model/Node.Companion/asPropertyOrNull/it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/-companion/as-property-or-null.html +$dokka.location:it.unibo.alchemist.model/Node///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/index.html +$dokka.location:it.unibo.alchemist.model/Node/addProperty/#it.unibo.alchemist.model.NodeProperty[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/add-property.html +$dokka.location:it.unibo.alchemist.model/Node/addReaction/#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/add-reaction.html +$dokka.location:it.unibo.alchemist.model/Node/asProperty/#java.lang.Class[TypeParam(bounds=[it.unibo.alchemist.model.NodeProperty[TypeParam(bounds=[kotlin.Any?])]])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/as-property.html +$dokka.location:it.unibo.alchemist.model/Node/asProperty/#kotlin.reflect.KClass[TypeParam(bounds=[it.unibo.alchemist.model.NodeProperty[TypeParam(bounds=[kotlin.Any?])]])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/as-property.html +$dokka.location:it.unibo.alchemist.model/Node/asPropertyOrNull/#java.lang.Class[TypeParam(bounds=[it.unibo.alchemist.model.NodeProperty[TypeParam(bounds=[kotlin.Any?])]])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/as-property-or-null.html +$dokka.location:it.unibo.alchemist.model/Node/asPropertyOrNull/#kotlin.reflect.KClass[TypeParam(bounds=[it.unibo.alchemist.model.NodeProperty[TypeParam(bounds=[kotlin.Any?])]])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/as-property-or-null.html +$dokka.location:it.unibo.alchemist.model/Node/cloneNode/#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/clone-node.html +$dokka.location:it.unibo.alchemist.model/Node/contains/#it.unibo.alchemist.model.Molecule/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/contains.html +$dokka.location:it.unibo.alchemist.model/Node/contents/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/contents.html +$dokka.location:it.unibo.alchemist.model/Node/equals/#kotlin.Any?/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/equals.html +$dokka.location:it.unibo.alchemist.model/Node/getConcentration/#it.unibo.alchemist.model.Molecule/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/get-concentration.html +$dokka.location:it.unibo.alchemist.model/Node/hashCode/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/hash-code.html +$dokka.location:it.unibo.alchemist.model/Node/id/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/id.html +$dokka.location:it.unibo.alchemist.model/Node/moleculeCount/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/molecule-count.html +$dokka.location:it.unibo.alchemist.model/Node/properties/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/properties.html +$dokka.location:it.unibo.alchemist.model/Node/reactions/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/reactions.html +$dokka.location:it.unibo.alchemist.model/Node/removeConcentration/#it.unibo.alchemist.model.Molecule/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/remove-concentration.html +$dokka.location:it.unibo.alchemist.model/Node/removeReaction/#it.unibo.alchemist.model.Reaction[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/remove-reaction.html +$dokka.location:it.unibo.alchemist.model/Node/setConcentration/#it.unibo.alchemist.model.Molecule#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node/set-concentration.html +$dokka.location:it.unibo.alchemist.model/NodeProperty///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node-property/index.html +$dokka.location:it.unibo.alchemist.model/NodeProperty/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node-property/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model/NodeProperty/node/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-node-property/node.html +$dokka.location:it.unibo.alchemist.model/Obstacle///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-obstacle/index.html +$dokka.location:it.unibo.alchemist.model/Obstacle/id/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-obstacle/id.html +$dokka.location:it.unibo.alchemist.model/Obstacle/nearestIntersection/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-obstacle/nearest-intersection.html +$dokka.location:it.unibo.alchemist.model/Obstacle/next/#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])#TypeParam(bounds=[it.unibo.alchemist.model.geometry.Vector[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-obstacle/next.html +$dokka.location:it.unibo.alchemist.model/Position///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position/index.html +$dokka.location:it.unibo.alchemist.model/Position/boundingBox/#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position/bounding-box.html +$dokka.location:it.unibo.alchemist.model/Position/coordinates/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position/coordinates.html +$dokka.location:it.unibo.alchemist.model/Position/dimensions/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position/dimensions.html +$dokka.location:it.unibo.alchemist.model/Position/distanceTo/#TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position/distance-to.html +$dokka.location:it.unibo.alchemist.model/Position/getCoordinate/#kotlin.Int/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position/get-coordinate.html +$dokka.location:it.unibo.alchemist.model/Position/minus/#kotlin.DoubleArray/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position/minus.html +$dokka.location:it.unibo.alchemist.model/Position/plus/#kotlin.DoubleArray/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position/plus.html +$dokka.location:it.unibo.alchemist.model/Position2D///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position2-d/index.html +$dokka.location:it.unibo.alchemist.model/Position2D/getCoordinate/#kotlin.Int/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position2-d/get-coordinate.html +$dokka.location:it.unibo.alchemist.model/Position2D/x/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position2-d/x.html +$dokka.location:it.unibo.alchemist.model/Position2D/y/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-position2-d/y.html +$dokka.location:it.unibo.alchemist.model/Reaction///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-reaction/index.html +$dokka.location:it.unibo.alchemist.model/Reaction/cloneOnNewNode/#it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-reaction/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model/Reaction/inputContext/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-reaction/input-context.html +$dokka.location:it.unibo.alchemist.model/Reaction/node/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-reaction/node.html +$dokka.location:it.unibo.alchemist.model/Reaction/outputContext/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-reaction/output-context.html +$dokka.location:it.unibo.alchemist.model/TerminationPredicate///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-termination-predicate/index.html +$dokka.location:it.unibo.alchemist.model/TerminationPredicate/invoke/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-termination-predicate/invoke.html +$dokka.location:it.unibo.alchemist.model/TerminationPredicate/or/#it.unibo.alchemist.model.TerminationPredicate[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-termination-predicate/or.html +$dokka.location:it.unibo.alchemist.model/TerminationPredicate/test/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-termination-predicate/test.html +$dokka.location:it.unibo.alchemist.model/Time.Companion///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/-companion/index.html +$dokka.location:it.unibo.alchemist.model/Time.Companion/INFINITY/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/-companion/-i-n-f-i-n-i-t-y.html +$dokka.location:it.unibo.alchemist.model/Time.Companion/NEGATIVE_INFINITY/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/-companion/-n-e-g-a-t-i-v-e_-i-n-f-i-n-i-t-y.html +$dokka.location:it.unibo.alchemist.model/Time.Companion/ZERO/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/-companion/-z-e-r-o.html +$dokka.location:it.unibo.alchemist.model/Time///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/index.html +$dokka.location:it.unibo.alchemist.model/Time/isFinite/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/is-finite.html +$dokka.location:it.unibo.alchemist.model/Time/isInfinite/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/is-infinite.html +$dokka.location:it.unibo.alchemist.model/Time/minus/#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/minus.html +$dokka.location:it.unibo.alchemist.model/Time/plus/#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/plus.html +$dokka.location:it.unibo.alchemist.model/Time/times/#kotlin.Double/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/times.html +$dokka.location:it.unibo.alchemist.model/Time/toDouble/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time/to-double.html +$dokka.location:it.unibo.alchemist.model/TimeDistribution///PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time-distribution/index.html +$dokka.location:it.unibo.alchemist.model/TimeDistribution/cloneOnNewNode/#it.unibo.alchemist.model.Node#it.unibo.alchemist.model.Time/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time-distribution/clone-on-new-node.html +$dokka.location:it.unibo.alchemist.model/TimeDistribution/getNextOccurence/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time-distribution/get-next-occurence.html +$dokka.location:it.unibo.alchemist.model/TimeDistribution/getRate/#/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time-distribution/get-rate.html +$dokka.location:it.unibo.alchemist.model/TimeDistribution/update/#it.unibo.alchemist.model.Time#boolean#double#it.unibo.alchemist.model.Environment/PointingToDeclaration/alchemist-api/it.unibo.alchemist.model/-time-distribution/update.html +it.unibo.alchemist.boundary +it.unibo.alchemist.core +it.unibo.alchemist.model +it.unibo.alchemist.model.geometry diff --git a/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list b/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list new file mode 100644 index 0000000000..415747ae38 --- /dev/null +++ b/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list @@ -0,0 +1,282 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:it.unibo.alchemist.boundary.launchers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/index.html +$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/index.html +$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/WebRendererLauncher/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/-web-renderer-launcher.html +$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/launch/#it.unibo.alchemist.boundary.Loader/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/launch.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//Button/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButtonGroup/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/active/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/active.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/disabled/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/disabled.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/onClick/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/on-click.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/variant.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/defaultValue/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/default-value.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/name.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/onChange/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/on-change.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/size/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/size.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/type/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/type.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/id.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/value/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/value.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//Modal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalBody/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-body.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalFooter/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-footer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalHeader/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalTitle/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps/closeButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/close-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/onHide/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/on-hide.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/show/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/show.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps/className/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/class-name.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//Navbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//NavbarBrand/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-brand.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/bg/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/bg.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/variant.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/client/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/client.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/endpoint/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/endpoint.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentClient/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-client.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentServer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-server.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/getSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/get-simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/pauseSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/pause-simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/playSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/play-simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppContent/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-content.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppNavbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-navbar.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//PlayButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//RenderModeButtons/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-render-mode-buttons.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//WarningModal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps/status/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/message/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/message.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/title/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/title.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic//updateState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.client.logic.UpdateStateStrategy#it.unibo.alchemist.boundary.webui.client.logic.AutoRenderModeStrategy/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/update-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/invoke.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/HwAutoRenderModeStrategy/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/-hw-auto-render-mode-strategy.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/invoke.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/minHwConcurrency/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/min-hw-concurrency.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/RESTUpdateStateStrategy/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/-r-e-s-t-update-state-strategy.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/client-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/retrieve-simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/server-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/client-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/retrieve-simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/server-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/SetBitmap/#korlibs.image.bitmap.Bitmap?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/-set-bitmap.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/bitmap.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/SetPlayButton/#it.unibo.alchemist.boundary.webui.common.utility.Action/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/-set-play-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/action/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/action.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/SetRenderMode/#it.unibo.alchemist.boundary.webui.common.model.RenderMode/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/-set-render-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/render-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/SetStatusSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/-set-status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//bitmapReducer/#korlibs.image.bitmap.Bitmap?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/bitmap-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//playButtonReducer/#it.unibo.alchemist.boundary.webui.common.utility.Action#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/play-button-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//renderModeReducer/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/render-mode-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//statusSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/status-surrogate-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state//rootReducer/#it.unibo.alchemist.boundary.webui.client.state.ClientState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/root-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/ClientState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.common.utility.Action#korlibs.image.bitmap.Bitmap?#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/-client-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/bitmap.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/playButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/play-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/render-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/store.html +$dokka.location:it.unibo.alchemist.boundary.webui.client////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client//App/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/-app.html +$dokka.location:it.unibo.alchemist.boundary.webui.client//main/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/main.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//decodeEnvironmentSurrogate/kotlinx.serialization.json.Json#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/decode-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//encodeEnvironmentSurrogate/kotlinx.serialization.json.Json#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/encode-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//jsonFormat/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/json-format.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules/concentrationModule/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/concentration-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EmptyConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-empty-concentration-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/polymorphicSerializer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/polymorphic-serializer.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/uninitializedEnvironment/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/uninitialized-environment.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/EnvironmentSurrogate/#kotlin.Int#kotlin.collections.List[it.unibo.alchemist.boundary.webui.common.model.surrogate.NodeSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/nodes/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/nodes.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/GeneralPositionSurrogate/#kotlin.DoubleArray#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/-general-position-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/equals/#kotlin.Any?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/equals.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/hashCode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/hash-code.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/MoleculeSurrogate/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/-molecule-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/name.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/descriptor.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/deserialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/serialize/#kotlinx.serialization.encoding.Encoder#it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/serialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/NodeSurrogate/#kotlin.Int#kotlin.collections.Map[it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate,TypeParam(bounds=[kotlin.Any])]#TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/-node-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/contents/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/contents.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/id.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/position/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/position.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/Position2DSurrogate/#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/-position2-d-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/x/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/x.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/y/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/y.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.INIT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-i-n-i-t/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.PAUSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-p-a-u-s-e-d/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.READY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-e-a-d-y/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.RUNNING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-u-n-n-i-n-g/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.TERMINATED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-t-e-r-m-i-n-a-t-e-d/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/entries.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/value-of.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/values.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.AUTO///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-a-u-t-o/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.CLIENT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-c-l-i-e-n-t/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.SERVER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-s-e-r-v-e-r/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/entries.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/value-of.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/values.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/descriptor.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/deserialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/serialize/#kotlinx.serialization.encoding.Encoder#korlibs.image.bitmap.Bitmap32/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/serialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/BitmapRenderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/-bitmap-renderer.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/render.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/render.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/CommonState/#it.unibo.alchemist.boundary.webui.common.renderer.Renderer[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate,korlibs.image.bitmap.Bitmap]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/-common-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/renderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/renderer.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PAUSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-a-u-s-e/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PLAY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-l-a-y/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/entries.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/value-of.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/values.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_CLIENT_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-c-l-i-e-n-t_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_SERVER_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-s-e-r-v-e-r_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PAUSE_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-a-u-s-e_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PLAY_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-l-a-y_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_STATUS_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-s-t-a-t-u-s_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//installModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/install-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//routingModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/routing-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//startBrowserModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/start-browser-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/EnvironmentMonitor/#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/-environment-monitor.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/finished/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/finished.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/initialized/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/initialized.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/stepDone/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Actionable[TypeParam(bounds=[kotlin.Any?])]?#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/step-done.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory/makeEnvironmentMonitor/#it.unibo.alchemist.model.Environment[*,*]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/make-environment-monitor.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes//mainRoute/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/main-route.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentClientMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-client-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentServerMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-server-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPause/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-pause.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPlay/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-play.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationStatus/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/SetEnvironmentSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/-set-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/SetSimulation/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/-set-simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//environmentSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/environment-surrogate-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//simulationReducer/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/simulation-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state//rootReducer/#it.unibo.alchemist.boundary.webui.server.state.ServerState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/root-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/ServerState/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/-server-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/store.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toMoleculeSurrogate/it.unibo.alchemist.model.Molecule#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-molecule-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toNodeSurrogate/it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-node-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toStatusSurrogate/it.unibo.alchemist.core.Status#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate/toEmptyConcentration/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/to-empty-concentration.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate/toSuitablePositionSurrogate/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/to-suitable-position-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion/respond/io.ktor.server.routing.RoutingContext#it.unibo.alchemist.boundary.webui.server.utility.Response[TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/respond.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/Response/#io.ktor.http.HttpStatusCode#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-response.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/code/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/code.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/content/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/content.html +it.unibo.alchemist.boundary.launchers +it.unibo.alchemist.boundary.webui.client +it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons +it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal +it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar +it.unibo.alchemist.boundary.webui.client.api +it.unibo.alchemist.boundary.webui.client.api.utility +it.unibo.alchemist.boundary.webui.client.components +it.unibo.alchemist.boundary.webui.client.logic +it.unibo.alchemist.boundary.webui.client.state +it.unibo.alchemist.boundary.webui.client.state.actions +it.unibo.alchemist.boundary.webui.client.state.reducers +it.unibo.alchemist.boundary.webui.common.model +it.unibo.alchemist.boundary.webui.common.model.serialization +it.unibo.alchemist.boundary.webui.common.model.surrogate +it.unibo.alchemist.boundary.webui.common.renderer +it.unibo.alchemist.boundary.webui.common.state +it.unibo.alchemist.boundary.webui.common.utility +it.unibo.alchemist.boundary.webui.server.modules +it.unibo.alchemist.boundary.webui.server.monitor +it.unibo.alchemist.boundary.webui.server.routes +it.unibo.alchemist.boundary.webui.server.state +it.unibo.alchemist.boundary.webui.server.state.actions +it.unibo.alchemist.boundary.webui.server.state.reducers +it.unibo.alchemist.boundary.webui.server.surrogates.utility +it.unibo.alchemist.boundary.webui.server.utility diff --git a/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list b/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list new file mode 100644 index 0000000000..a9c06fdff1 --- /dev/null +++ b/dokka-cache/org.danilopianini/java-quadtree/1.0.2.list @@ -0,0 +1,25 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:org.danilopianini.util////PointingToDeclaration/java-quadtree/org.danilopianini.util/index.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree.Companion///PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-companion/index.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree.Companion/DEFAULT_CAPACITY/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-companion/-d-e-f-a-u-l-t_-c-a-p-a-c-i-t-y.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree///PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/index.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/FlexibleQuadTree/#kotlin.Int/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/-flexible-quad-tree.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/dimensions/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/dimensions.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/insert.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/insert.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/maxElementsNumber/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/max-elements-number.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/move.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/move.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/query/#kotlin.Array[kotlin.DoubleArray]/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/query.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/query/#kotlin.Double#kotlin.Double#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/query.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.Double#kotlin.Double/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/remove.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/remove.html +$dokka.location:org.danilopianini.util/FlexibleQuadTree/toString/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-flexible-quad-tree/to-string.html +$dokka.location:org.danilopianini.util/SpatialIndex///PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/index.html +$dokka.location:org.danilopianini.util/SpatialIndex/dimensions/#/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/dimensions.html +$dokka.location:org.danilopianini.util/SpatialIndex/insert/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/insert.html +$dokka.location:org.danilopianini.util/SpatialIndex/move/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/move.html +$dokka.location:org.danilopianini.util/SpatialIndex/query/#kotlin.Array[kotlin.DoubleArray]/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/query.html +$dokka.location:org.danilopianini.util/SpatialIndex/remove/#TypeParam(bounds=[kotlin.Any?])#kotlin.DoubleArray/PointingToDeclaration/java-quadtree/org.danilopianini.util/-spatial-index/remove.html +org.danilopianini.util diff --git a/dokka-cache/org.danilopianini/listset/0.3.9.list b/dokka-cache/org.danilopianini/listset/0.3.9.list new file mode 100644 index 0000000000..9b56bbd751 --- /dev/null +++ b/dokka-cache/org.danilopianini/listset/0.3.9.list @@ -0,0 +1 @@ +org.danilopianini.util From 2f60464232a04ed191c237eacaea76255db2aff3 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 20:04:50 +0000 Subject: [PATCH 083/196] chore(build): update the javadoc.io cache --- .../io.ktor/ktor-server-netty/3.3.3.list | 81 +++++ .../alchemist-web-renderer/42.3.18.list | 282 ------------------ .../org.mockito/mockito-core/5.20.0.list | 20 ++ 3 files changed, 101 insertions(+), 282 deletions(-) create mode 100644 dokka-cache/io.ktor/ktor-server-netty/3.3.3.list delete mode 100644 dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list create mode 100644 dokka-cache/org.mockito/mockito-core/5.20.0.list diff --git a/dokka-cache/io.ktor/ktor-server-netty/3.3.3.list b/dokka-cache/io.ktor/ktor-server-netty/3.3.3.list new file mode 100644 index 0000000000..697f5a7619 --- /dev/null +++ b/dokka-cache/io.ktor/ktor-server-netty/3.3.3.list @@ -0,0 +1,81 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:io.ktor.server.netty.cio////PointingToDeclaration/ktor-server-netty/io.ktor.server.netty.cio/index.html +$dokka.location:io.ktor.server.netty.cio/NettyResponsePipelineException///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty.cio/-netty-response-pipeline-exception/index.html +$dokka.location:io.ktor.server.netty.cio/NettyResponsePipelineException/NettyResponsePipelineException/#kotlin.String/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty.cio/-netty-response-pipeline-exception/-netty-response-pipeline-exception.html +$dokka.location:io.ktor.server.netty////PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/index.html +$dokka.location:io.ktor.server.netty//suspendAwait/io.netty.util.concurrent.Future[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/suspend-await.html +$dokka.location:io.ktor.server.netty//suspendAwait/io.netty.util.concurrent.Future[TypeParam(bounds=[kotlin.Any?])]#kotlin.Function2[kotlin.Throwable,kotlin.coroutines.Continuation[TypeParam(bounds=[kotlin.Any?])],kotlin.Unit]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/suspend-await.html +$dokka.location:io.ktor.server.netty//suspendWriteAwait/io.netty.util.concurrent.Future[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/suspend-write-await.html +$dokka.location:io.ktor.server.netty/EngineMain///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-engine-main/index.html +$dokka.location:io.ktor.server.netty/EngineMain/createServer/#kotlin.Array[kotlin.String]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-engine-main/create-server.html +$dokka.location:io.ktor.server.netty/EngineMain/main/#kotlin.Array[kotlin.String]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-engine-main/main.html +$dokka.location:io.ktor.server.netty/EventLoopGroupProxy.Companion///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/-companion/index.html +$dokka.location:io.ktor.server.netty/EventLoopGroupProxy.Companion/create/#kotlin.Int/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/-companion/create.html +$dokka.location:io.ktor.server.netty/EventLoopGroupProxy///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/index.html +$dokka.location:io.ktor.server.netty/EventLoopGroupProxy/EventLoopGroupProxy/#kotlin.reflect.KClass[io.netty.channel.socket.ServerSocketChannel]#io.netty.channel.EventLoopGroup/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/-event-loop-group-proxy.html +$dokka.location:io.ktor.server.netty/EventLoopGroupProxy/channel/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/channel.html +$dokka.location:io.ktor.server.netty/EventLoopGroupProxy/isShutdown/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/is-shutdown.html +$dokka.location:io.ktor.server.netty/EventLoopGroupProxy/isShuttingDown/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/is-shutting-down.html +$dokka.location:io.ktor.server.netty/EventLoopGroupProxy/isTerminated/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-event-loop-group-proxy/is-terminated.html +$dokka.location:io.ktor.server.netty/Netty///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty/index.html +$dokka.location:io.ktor.server.netty/Netty/configuration/#kotlin.Function1[io.ktor.server.netty.NettyApplicationEngine.Configuration,kotlin.Unit]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty/configuration.html +$dokka.location:io.ktor.server.netty/Netty/create/#io.ktor.server.application.ApplicationEnvironment#io.ktor.events.Events#kotlin.Boolean#io.ktor.server.netty.NettyApplicationEngine.Configuration#kotlin.Function0[io.ktor.server.application.Application]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty/create.html +$dokka.location:io.ktor.server.netty/NettyApplicationCall///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/index.html +$dokka.location:io.ktor.server.netty/NettyApplicationCall/NettyApplicationCall/#io.ktor.server.application.Application#io.netty.channel.ChannelHandlerContext#kotlin.Any/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/-netty-application-call.html +$dokka.location:io.ktor.server.netty/NettyApplicationCall/context/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/context.html +$dokka.location:io.ktor.server.netty/NettyApplicationCall/request/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/request.html +$dokka.location:io.ktor.server.netty/NettyApplicationCall/response/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/response.html +$dokka.location:io.ktor.server.netty/NettyApplicationCall/responseWriteJob/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-call/response-write-job.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/index.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/Configuration/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/-configuration.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/channelPipelineConfig/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/channel-pipeline-config.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/configureBootstrap/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/configure-bootstrap.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/enableH2c/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/enable-h2c.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/enableHttp2/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/enable-http2.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/httpServerCodec/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/http-server-codec.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/maxChunkSize/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/max-chunk-size.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/maxHeaderSize/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/max-header-size.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/maxInitialLineLength/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/max-initial-line-length.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/requestReadTimeoutSeconds/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/request-read-timeout-seconds.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/responseWriteTimeoutSeconds/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/response-write-timeout-seconds.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/runningLimit/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/running-limit.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/shareWorkGroup/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/share-work-group.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine.Configuration/tcpKeepAlive/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-configuration/tcp-keep-alive.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/index.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine/NettyApplicationEngine/#io.ktor.server.application.ApplicationEnvironment#io.ktor.events.Events#kotlin.Boolean#io.ktor.server.netty.NettyApplicationEngine.Configuration#kotlin.Function0[io.ktor.server.application.Application]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/-netty-application-engine.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine/configuration/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/configuration.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine/start/#kotlin.Boolean/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/start.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine/stop/#kotlin.Long#kotlin.Long/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/stop.html +$dokka.location:io.ktor.server.netty/NettyApplicationEngine/toString/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-engine/to-string.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequest///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/index.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequest/NettyApplicationRequest/#io.ktor.server.application.PipelineCall#kotlin.coroutines.CoroutineContext#io.netty.channel.ChannelHandlerContext#io.ktor.utils.io.ByteReadChannel#kotlin.String#kotlin.Boolean/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/-netty-application-request.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequest/close/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/close.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequest/context/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/context.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequest/cookies/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/cookies.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequest/coroutineContext/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/coroutine-context.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequest/queryParameters/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/query-parameters.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequest/rawQueryParameters/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request/raw-query-parameters.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/index.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/NettyApplicationRequestHeaders/#io.netty.handler.codec.http.HttpRequest/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/-netty-application-request-headers.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/caseInsensitiveName/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/case-insensitive-name.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/contains/#kotlin.String#kotlin.String/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/contains.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/contains/#kotlin.String/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/contains.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/entries/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/entries.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/forEach/#kotlin.Function2[kotlin.String,kotlin.collections.List[kotlin.String],kotlin.Unit]/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/for-each.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/get/#kotlin.String/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/get.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/getAll/#kotlin.String/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/get-all.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/isEmpty/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/is-empty.html +$dokka.location:io.ktor.server.netty/NettyApplicationRequestHeaders/names/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-request-headers/names.html +$dokka.location:io.ktor.server.netty/NettyApplicationResponse.Companion///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/-companion/index.html +$dokka.location:io.ktor.server.netty/NettyApplicationResponse.Companion/responseStatusCache/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/-companion/response-status-cache.html +$dokka.location:io.ktor.server.netty/NettyApplicationResponse///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/index.html +$dokka.location:io.ktor.server.netty/NettyApplicationResponse/NettyApplicationResponse/#io.ktor.server.netty.NettyApplicationCall#io.netty.channel.ChannelHandlerContext#kotlin.coroutines.CoroutineContext#kotlin.coroutines.CoroutineContext/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/-netty-application-response.html +$dokka.location:io.ktor.server.netty/NettyApplicationResponse/cancel/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/cancel.html +$dokka.location:io.ktor.server.netty/NettyApplicationResponse/responseMessage/#/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-application-response/response-message.html +$dokka.location:io.ktor.server.netty/NettyChannelInitializer.Companion///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-channel-initializer/-companion/index.html +$dokka.location:io.ktor.server.netty/NettyChannelInitializer///PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-channel-initializer/index.html +$dokka.location:io.ktor.server.netty/NettyChannelInitializer/NettyChannelInitializer/#kotlin.Function0[io.ktor.server.application.Application]#io.ktor.server.engine.EnginePipeline#io.ktor.server.application.ApplicationEnvironment#io.netty.util.concurrent.EventExecutorGroup#kotlin.coroutines.CoroutineContext#kotlin.coroutines.CoroutineContext#io.ktor.server.engine.EngineConnectorConfig#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Function0[io.netty.handler.codec.http.HttpServerCodec]#kotlin.Function1[io.netty.channel.ChannelPipeline,kotlin.Unit]#kotlin.Boolean#kotlin.Boolean/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-channel-initializer/-netty-channel-initializer.html +$dokka.location:io.ktor.server.netty/NettyChannelInitializer/NettyChannelInitializer/#kotlin.Function0[io.ktor.server.application.Application]#io.ktor.server.engine.EnginePipeline#io.ktor.server.application.ApplicationEnvironment#io.netty.util.concurrent.EventExecutorGroup#kotlin.coroutines.CoroutineContext#kotlin.coroutines.CoroutineContext#io.ktor.server.engine.EngineConnectorConfig#kotlin.Int#kotlin.Int#kotlin.Int#kotlin.Function0[io.netty.handler.codec.http.HttpServerCodec]#kotlin.Function1[io.netty.channel.ChannelPipeline,kotlin.Unit]#kotlin.Boolean/PointingToDeclaration/ktor-server-netty/io.ktor.server.netty/-netty-channel-initializer/-netty-channel-initializer.html +io.ktor.server.netty +io.ktor.server.netty.cio diff --git a/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list b/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list deleted file mode 100644 index 415747ae38..0000000000 --- a/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list +++ /dev/null @@ -1,282 +0,0 @@ -$dokka.format:html-v1 -$dokka.linkExtension:html -$dokka.location:it.unibo.alchemist.boundary.launchers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/index.html -$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/index.html -$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/WebRendererLauncher/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/-web-renderer-launcher.html -$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/launch/#it.unibo.alchemist.boundary.Loader/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/launch.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//Button/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButtonGroup/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/active/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/active.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/disabled/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/disabled.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/onClick/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/on-click.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/variant.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/defaultValue/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/default-value.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/name.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/onChange/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/on-change.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/size/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/size.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/type/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/type.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/id.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/value/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/value.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//Modal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalBody/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-body.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalFooter/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-footer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalHeader/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalTitle/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps/closeButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/close-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/onHide/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/on-hide.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/show/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/show.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps/className/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/class-name.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//Navbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//NavbarBrand/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-brand.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/bg/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/bg.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/variant.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/client/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/client.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/endpoint/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/endpoint.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentClient/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-client.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentServer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-server.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/getSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/get-simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/pauseSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/pause-simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/playSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/play-simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppContent/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-content.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppNavbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-navbar.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//PlayButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//RenderModeButtons/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-render-mode-buttons.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components//WarningModal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps/status/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/message/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/message.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/title/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/title.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic//updateState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.client.logic.UpdateStateStrategy#it.unibo.alchemist.boundary.webui.client.logic.AutoRenderModeStrategy/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/update-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/invoke.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/HwAutoRenderModeStrategy/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/-hw-auto-render-mode-strategy.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/invoke.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/minHwConcurrency/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/min-hw-concurrency.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/RESTUpdateStateStrategy/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/-r-e-s-t-update-state-strategy.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/client-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/retrieve-simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/server-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/client-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/retrieve-simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/server-computation.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/SetBitmap/#korlibs.image.bitmap.Bitmap?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/-set-bitmap.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/bitmap.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/SetPlayButton/#it.unibo.alchemist.boundary.webui.common.utility.Action/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/-set-play-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/action/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/action.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/SetRenderMode/#it.unibo.alchemist.boundary.webui.common.model.RenderMode/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/-set-render-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/render-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/SetStatusSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/-set-status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//bitmapReducer/#korlibs.image.bitmap.Bitmap?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/bitmap-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//playButtonReducer/#it.unibo.alchemist.boundary.webui.common.utility.Action#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/play-button-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//renderModeReducer/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/render-mode-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//statusSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/status-surrogate-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state//rootReducer/#it.unibo.alchemist.boundary.webui.client.state.ClientState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/root-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/ClientState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.common.utility.Action#korlibs.image.bitmap.Bitmap?#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/-client-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/bitmap.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/playButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/play-button.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/render-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/store.html -$dokka.location:it.unibo.alchemist.boundary.webui.client////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.client//App/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/-app.html -$dokka.location:it.unibo.alchemist.boundary.webui.client//main/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/main.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//decodeEnvironmentSurrogate/kotlinx.serialization.json.Json#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/decode-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//encodeEnvironmentSurrogate/kotlinx.serialization.json.Json#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/encode-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//jsonFormat/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/json-format.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules/concentrationModule/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/concentration-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EmptyConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-empty-concentration-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/polymorphicSerializer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/polymorphic-serializer.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/uninitializedEnvironment/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/uninitialized-environment.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/EnvironmentSurrogate/#kotlin.Int#kotlin.collections.List[it.unibo.alchemist.boundary.webui.common.model.surrogate.NodeSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/nodes/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/nodes.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/GeneralPositionSurrogate/#kotlin.DoubleArray#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/-general-position-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/coordinates.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/equals/#kotlin.Any?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/equals.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/hashCode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/hash-code.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/MoleculeSurrogate/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/-molecule-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/name.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/descriptor.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/deserialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/serialize/#kotlinx.serialization.encoding.Encoder#it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/serialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/NodeSurrogate/#kotlin.Int#kotlin.collections.Map[it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate,TypeParam(bounds=[kotlin.Any])]#TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/-node-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/contents/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/contents.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/id.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/position/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/position.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/Position2DSurrogate/#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/-position2-d-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/coordinates.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/x/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/x.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/y/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/y.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/coordinates.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/dimensions.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.INIT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-i-n-i-t/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.PAUSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-p-a-u-s-e-d/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.READY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-e-a-d-y/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.RUNNING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-u-n-n-i-n-g/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.TERMINATED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-t-e-r-m-i-n-a-t-e-d/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/entries.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/value-of.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/values.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.AUTO///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-a-u-t-o/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.CLIENT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-c-l-i-e-n-t/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.SERVER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-s-e-r-v-e-r/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/entries.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/value-of.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/values.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/descriptor.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/deserialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/serialize/#kotlinx.serialization.encoding.Encoder#korlibs.image.bitmap.Bitmap32/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/serialize.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/BitmapRenderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/-bitmap-renderer.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/render.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/render.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/CommonState/#it.unibo.alchemist.boundary.webui.common.renderer.Renderer[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate,korlibs.image.bitmap.Bitmap]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/-common-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/renderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/renderer.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PAUSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-a-u-s-e/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PLAY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-l-a-y/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/entries.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/value-of.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/values.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_CLIENT_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-c-l-i-e-n-t_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_SERVER_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-s-e-r-v-e-r_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PAUSE_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-a-u-s-e_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PLAY_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-l-a-y_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_STATUS_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-s-t-a-t-u-s_-p-a-t-h.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//installModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/install-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//routingModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/routing-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//startBrowserModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/start-browser-module.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/EnvironmentMonitor/#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/-environment-monitor.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/finished/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/finished.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/initialized/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/initialized.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/stepDone/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Actionable[TypeParam(bounds=[kotlin.Any?])]?#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/step-done.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory/makeEnvironmentMonitor/#it.unibo.alchemist.model.Environment[*,*]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/make-environment-monitor.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes//mainRoute/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/main-route.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentClientMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-client-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentServerMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-server-mode.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPause/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-pause.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPlay/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-play.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationStatus/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-status.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/SetEnvironmentSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/-set-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/SetSimulation/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/-set-simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//environmentSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/environment-surrogate-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//simulationReducer/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/simulation-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state//rootReducer/#it.unibo.alchemist.boundary.webui.server.state.ServerState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/root-reducer.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/ServerState/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/-server-state.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/simulation.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/store.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toMoleculeSurrogate/it.unibo.alchemist.model.Molecule#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-molecule-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toNodeSurrogate/it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-node-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toStatusSurrogate/it.unibo.alchemist.core.Status#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-status-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate/toEmptyConcentration/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/to-empty-concentration.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate/toSuitablePositionSurrogate/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/to-suitable-position-surrogate.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion/respond/io.ktor.server.routing.RoutingContext#it.unibo.alchemist.boundary.webui.server.utility.Response[TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/respond.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/index.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/Response/#io.ktor.http.HttpStatusCode#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-response.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/code/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/code.html -$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/content/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/content.html -it.unibo.alchemist.boundary.launchers -it.unibo.alchemist.boundary.webui.client -it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons -it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal -it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar -it.unibo.alchemist.boundary.webui.client.api -it.unibo.alchemist.boundary.webui.client.api.utility -it.unibo.alchemist.boundary.webui.client.components -it.unibo.alchemist.boundary.webui.client.logic -it.unibo.alchemist.boundary.webui.client.state -it.unibo.alchemist.boundary.webui.client.state.actions -it.unibo.alchemist.boundary.webui.client.state.reducers -it.unibo.alchemist.boundary.webui.common.model -it.unibo.alchemist.boundary.webui.common.model.serialization -it.unibo.alchemist.boundary.webui.common.model.surrogate -it.unibo.alchemist.boundary.webui.common.renderer -it.unibo.alchemist.boundary.webui.common.state -it.unibo.alchemist.boundary.webui.common.utility -it.unibo.alchemist.boundary.webui.server.modules -it.unibo.alchemist.boundary.webui.server.monitor -it.unibo.alchemist.boundary.webui.server.routes -it.unibo.alchemist.boundary.webui.server.state -it.unibo.alchemist.boundary.webui.server.state.actions -it.unibo.alchemist.boundary.webui.server.state.reducers -it.unibo.alchemist.boundary.webui.server.surrogates.utility -it.unibo.alchemist.boundary.webui.server.utility diff --git a/dokka-cache/org.mockito/mockito-core/5.20.0.list b/dokka-cache/org.mockito/mockito-core/5.20.0.list new file mode 100644 index 0000000000..7ef36c473b --- /dev/null +++ b/dokka-cache/org.mockito/mockito-core/5.20.0.list @@ -0,0 +1,20 @@ +module:org.mockito +org.mockito +org.mockito.configuration +org.mockito.creation.instance +org.mockito.exceptions.base +org.mockito.exceptions.misusing +org.mockito.exceptions.stacktrace +org.mockito.exceptions.verification +org.mockito.exceptions.verification.junit +org.mockito.exceptions.verification.opentest4j +org.mockito.hamcrest +org.mockito.invocation +org.mockito.junit +org.mockito.listeners +org.mockito.mock +org.mockito.plugins +org.mockito.quality +org.mockito.session +org.mockito.stubbing +org.mockito.verification From 3f95b7368eab352a5432928bdb1dc594b256e8c6 Mon Sep 17 00:00:00 2001 From: "Danilo Pianini [bot]" Date: Mon, 1 Dec 2025 20:32:31 +0000 Subject: [PATCH 084/196] chore(build): update the javadoc.io cache --- .../alchemist-web-renderer/42.3.18.list | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list diff --git a/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list b/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list new file mode 100644 index 0000000000..415747ae38 --- /dev/null +++ b/dokka-cache/it.unibo.alchemist/alchemist-web-renderer/42.3.18.list @@ -0,0 +1,282 @@ +$dokka.format:html-v1 +$dokka.linkExtension:html +$dokka.location:it.unibo.alchemist.boundary.launchers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/index.html +$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/index.html +$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/WebRendererLauncher/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/-web-renderer-launcher.html +$dokka.location:it.unibo.alchemist.boundary.launchers/WebRendererLauncher/launch/#it.unibo.alchemist.boundary.Loader/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.launchers/-web-renderer-launcher/launch.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//Button/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons//ToggleButtonGroup/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/active/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/active.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/disabled/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/disabled.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/onClick/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/on-click.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ButtonProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-button-props/variant.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/defaultValue/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/default-value.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/name.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/onChange/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/on-change.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/size/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/size.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonGroupProps/type/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-group-props/type.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/id.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/ToggleButtonProps/value/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons/-toggle-button-props/value.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//Modal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalBody/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-body.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalFooter/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-footer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalHeader/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal//ModalTitle/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalHeaderProps/closeButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-header-props/close-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/onHide/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/on-hide.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalProps/show/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-props/show.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/ModalTitleProps/className/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal/-modal-title-props/class-name.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//Navbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar//NavbarBrand/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-brand.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/bg/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/bg.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/NavbarProps/variant/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar/-navbar-props/variant.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/client/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/client.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api.utility/JsonClient/endpoint/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api.utility/-json-client/endpoint.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentClient/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-client.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/EnvironmentApi/getEnvironmentServer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-environment-api/get-environment-server.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/getSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/get-simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/pauseSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/pause-simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.api/SimulationApi/playSimulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.api/-simulation-api/play-simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppContent/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-content.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//AppNavbar/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-app-navbar.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//PlayButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//RenderModeButtons/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-render-mode-buttons.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components//WarningModal/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/PlayButtonProps/status/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-play-button-props/status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/message/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/message.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.components/WarningModalProps/title/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.components/-warning-modal-props/title.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic//updateState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.client.logic.UpdateStateStrategy#it.unibo.alchemist.boundary.webui.client.logic.AutoRenderModeStrategy/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/update-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/AutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-auto-render-mode-strategy/invoke.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/HwAutoRenderModeStrategy/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/-hw-auto-render-mode-strategy.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/invoke/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/invoke.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/HwAutoRenderModeStrategy/minHwConcurrency/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-hw-auto-render-mode-strategy/min-hw-concurrency.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/RESTUpdateStateStrategy/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/-r-e-s-t-update-state-strategy.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/client-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/retrieve-simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/RESTUpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-r-e-s-t-update-state-strategy/server-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/clientComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/client-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/retrieveSimulationStatus/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/retrieve-simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.logic/UpdateStateStrategy/serverComputation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.logic/-update-state-strategy/server-computation.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/SetBitmap/#korlibs.image.bitmap.Bitmap?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/-set-bitmap.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetBitmap/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-bitmap/bitmap.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/SetPlayButton/#it.unibo.alchemist.boundary.webui.common.utility.Action/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/-set-play-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetPlayButton/action/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-play-button/action.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/SetRenderMode/#it.unibo.alchemist.boundary.webui.common.model.RenderMode/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/-set-render-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetRenderMode/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-render-mode/render-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/SetStatusSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/-set-status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.actions/SetStatusSurrogate/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.actions/-set-status-surrogate/status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//bitmapReducer/#korlibs.image.bitmap.Bitmap?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/bitmap-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//playButtonReducer/#it.unibo.alchemist.boundary.webui.common.utility.Action#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/play-button-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//renderModeReducer/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/render-mode-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state.reducers//statusSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state.reducers/status-surrogate-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state//rootReducer/#it.unibo.alchemist.boundary.webui.client.state.ClientState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/root-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/ClientState/#it.unibo.alchemist.boundary.webui.common.model.RenderMode#it.unibo.alchemist.boundary.webui.common.utility.Action#korlibs.image.bitmap.Bitmap?#it.unibo.alchemist.boundary.webui.common.model.surrogate.StatusSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/-client-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/bitmap/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/bitmap.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/playButton/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/play-button.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/renderMode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/render-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientState/statusSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-state/status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client.state/ClientStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client.state/-client-store/store.html +$dokka.location:it.unibo.alchemist.boundary.webui.client////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.client//App/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/-app.html +$dokka.location:it.unibo.alchemist.boundary.webui.client//main/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.client/main.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//decodeEnvironmentSurrogate/kotlinx.serialization.json.Json#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/decode-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//encodeEnvironmentSurrogate/kotlinx.serialization.json.Json#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/encode-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization//jsonFormat/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/json-format.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.serialization/SerializationModules/concentrationModule/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.serialization/-serialization-modules/concentration-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EmptyConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-empty-concentration-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/polymorphicSerializer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/polymorphic-serializer.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate.Companion/uninitializedEnvironment/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-companion/uninitialized-environment.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/EnvironmentSurrogate/#kotlin.Int#kotlin.collections.List[it.unibo.alchemist.boundary.webui.common.model.surrogate.NodeSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/EnvironmentSurrogate/nodes/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-environment-surrogate/nodes.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/GeneralPositionSurrogate/#kotlin.DoubleArray#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/-general-position-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/equals/#kotlin.Any?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/equals.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/GeneralPositionSurrogate/hashCode/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-general-position-surrogate/hash-code.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/MoleculeSurrogate/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/-molecule-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogate/name/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate/name.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/descriptor.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/deserialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/MoleculeSurrogateSerializer/serialize/#kotlinx.serialization.encoding.Encoder#it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-molecule-surrogate-serializer/serialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/NodeSurrogate/#kotlin.Int#kotlin.collections.Map[it.unibo.alchemist.boundary.webui.common.model.surrogate.MoleculeSurrogate,TypeParam(bounds=[kotlin.Any])]#TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/-node-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/contents/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/contents.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/id/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/id.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/NodeSurrogate/position/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-node-surrogate/position.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/Position2DSurrogate/#kotlin.Double#kotlin.Double/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/-position2-d-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/x/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/x.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/Position2DSurrogate/y/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position2-d-surrogate/y.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/coordinates/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/coordinates.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/PositionSurrogate/dimensions/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-position-surrogate/dimensions.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.INIT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-i-n-i-t/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.PAUSED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-p-a-u-s-e-d/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.READY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-e-a-d-y/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.RUNNING///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-r-u-n-n-i-n-g/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate.TERMINATED///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/-t-e-r-m-i-n-a-t-e-d/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/entries.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/value-of.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model.surrogate/StatusSurrogate/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model.surrogate/-status-surrogate/values.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.AUTO///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-a-u-t-o/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.CLIENT///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-c-l-i-e-n-t/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode.SERVER///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/-s-e-r-v-e-r/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/entries.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/value-of.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.model/RenderMode/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.model/-render-mode/values.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/descriptor/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/descriptor.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/deserialize/#kotlinx.serialization.encoding.Decoder/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/deserialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Bitmap32Serializer/serialize/#kotlinx.serialization.encoding.Encoder#korlibs.image.bitmap.Bitmap32/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap32-serializer/serialize.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/BitmapRenderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/-bitmap-renderer.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/BitmapRenderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-bitmap-renderer/render.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.renderer/Renderer/render/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.renderer/-renderer/render.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/CommonState/#it.unibo.alchemist.boundary.webui.common.renderer.Renderer[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate,korlibs.image.bitmap.Bitmap]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/-common-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.state/CommonState/renderer/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.state/-common-state/renderer.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PAUSE///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-a-u-s-e/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action.PLAY///PointingToDeclaration/{"org.jetbrains.dokka.links.EnumEntryDRIExtra":{"key":"org.jetbrains.dokka.links.EnumEntryDRIExtra"}}alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/-p-l-a-y/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/entries/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/entries.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/valueOf/#kotlin.String/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/value-of.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Action/values/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-action/values.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_CLIENT_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-c-l-i-e-n-t_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/ENVIRONMENT_SERVER_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-e-n-v-i-r-o-n-m-e-n-t_-s-e-r-v-e-r_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PAUSE_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-a-u-s-e_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_PLAY_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-p-l-a-y_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.common.utility/Routes/SIMULATION_STATUS_PATH/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.common.utility/-routes/-s-i-m-u-l-a-t-i-o-n_-s-t-a-t-u-s_-p-a-t-h.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//installModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/install-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//routingModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/routing-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.modules//startBrowserModule/io.ktor.server.application.Application#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.modules/start-browser-module.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/EnvironmentMonitor/#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/-environment-monitor.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/finished/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/finished.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/initialized/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/initialized.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitor/stepDone/#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#it.unibo.alchemist.model.Actionable[TypeParam(bounds=[kotlin.Any?])]?#it.unibo.alchemist.model.Time#kotlin.Long/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor/step-done.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.monitor/EnvironmentMonitorFactory/makeEnvironmentMonitor/#it.unibo.alchemist.model.Environment[*,*]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.monitor/-environment-monitor-factory/make-environment-monitor.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes//mainRoute/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/main-route.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentClientMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-client-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/EnvironmentRoute/environmentServerMode/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-environment-route/environment-server-mode.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPause/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-pause.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationActionPlay/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-action-play.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.routes/SimulationRoute/simulationStatus/io.ktor.server.routing.Route#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.routes/-simulation-route/simulation-status.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/SetEnvironmentSurrogate/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[TypeParam(bounds=[kotlin.Any]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/-set-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetEnvironmentSurrogate/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-environment-surrogate/environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/SetSimulation/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/-set-simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.actions/SetSimulation/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.actions/-set-simulation/simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//environmentSurrogateReducer/#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/environment-surrogate-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state.reducers//simulationReducer/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state.reducers/simulation-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state//rootReducer/#it.unibo.alchemist.boundary.webui.server.state.ServerState#kotlin.Any/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/root-reducer.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/ServerState/#it.unibo.alchemist.core.Simulation[kotlin.Any,kotlin.Nothing]?#it.unibo.alchemist.boundary.webui.common.model.surrogate.EnvironmentSurrogate[kotlin.Any,it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/-server-state.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/environmentSurrogate/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerState/simulation/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-state/simulation.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.state/ServerStore/store/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.state/-server-store/store.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toEnvironmentSurrogate/it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-environment-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toMoleculeSurrogate/it.unibo.alchemist.model.Molecule#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-molecule-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toNodeSurrogate/it.unibo.alchemist.model.Node[TypeParam(bounds=[kotlin.Any?])]#it.unibo.alchemist.model.Environment[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[it.unibo.alchemist.model.Position[^]])]#kotlin.Function1[TypeParam(bounds=[kotlin.Any?]),TypeParam(bounds=[kotlin.Any])]#kotlin.Function1[TypeParam(bounds=[it.unibo.alchemist.model.Position[^]]),TypeParam(bounds=[it.unibo.alchemist.boundary.webui.common.model.surrogate.PositionSurrogate])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-node-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility//toStatusSurrogate/it.unibo.alchemist.core.Status#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/to-status-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToConcentrationSurrogate/toEmptyConcentration/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-concentration-surrogate/to-empty-concentration.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.surrogates.utility/ToPositionSurrogate/toSuitablePositionSurrogate/#kotlin.Int/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.surrogates.utility/-to-position-surrogate/to-suitable-position-surrogate.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility////PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response.Companion/respond/io.ktor.server.routing.RoutingContext#it.unibo.alchemist.boundary.webui.server.utility.Response[TypeParam(bounds=[kotlin.Any])]/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-companion/respond.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response///PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/index.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/Response/#io.ktor.http.HttpStatusCode#TypeParam(bounds=[kotlin.Any?])/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/-response.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/code/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/code.html +$dokka.location:it.unibo.alchemist.boundary.webui.server.utility/Response/content/#/PointingToDeclaration/alchemist-web-renderer/it.unibo.alchemist.boundary.webui.server.utility/-response/content.html +it.unibo.alchemist.boundary.launchers +it.unibo.alchemist.boundary.webui.client +it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.buttons +it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.modal +it.unibo.alchemist.boundary.webui.client.adapters.reactBootstrap.navbar +it.unibo.alchemist.boundary.webui.client.api +it.unibo.alchemist.boundary.webui.client.api.utility +it.unibo.alchemist.boundary.webui.client.components +it.unibo.alchemist.boundary.webui.client.logic +it.unibo.alchemist.boundary.webui.client.state +it.unibo.alchemist.boundary.webui.client.state.actions +it.unibo.alchemist.boundary.webui.client.state.reducers +it.unibo.alchemist.boundary.webui.common.model +it.unibo.alchemist.boundary.webui.common.model.serialization +it.unibo.alchemist.boundary.webui.common.model.surrogate +it.unibo.alchemist.boundary.webui.common.renderer +it.unibo.alchemist.boundary.webui.common.state +it.unibo.alchemist.boundary.webui.common.utility +it.unibo.alchemist.boundary.webui.server.modules +it.unibo.alchemist.boundary.webui.server.monitor +it.unibo.alchemist.boundary.webui.server.routes +it.unibo.alchemist.boundary.webui.server.state +it.unibo.alchemist.boundary.webui.server.state.actions +it.unibo.alchemist.boundary.webui.server.state.reducers +it.unibo.alchemist.boundary.webui.server.surrogates.utility +it.unibo.alchemist.boundary.webui.server.utility From 1a83976e6da4a24056066748d572c77b9616f623 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 17:26:48 +0100 Subject: [PATCH 085/196] style(dsl-processor): cleanup `ConstructorFinder` --- .../dsl/processor/ConstructorFinder.kt | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt index fd9dd2d8f7..d675256ede 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt @@ -13,24 +13,19 @@ object ConstructorFinder { * Prefers the primary constructor, otherwise returns the constructor * with the most parameters. * - * @param classDecl The class declaration to find a constructor for + * @param classDeclaration The class declaration to find a constructor for * @return The found constructor, or null if no suitable constructor exists */ - fun findConstructor(classDecl: KSClassDeclaration): KSFunctionDeclaration? = - classDecl.primaryConstructor?.takeIf { isPublicConstructor(it) } ?: classDecl - .getAllFunctions() - .filter { function -> - val simpleName = function.simpleName.asString() - (simpleName == "" || simpleName == classDecl.simpleName.asString()) && - isPublicConstructor(function) - } - .sortedByDescending { it.parameters.size } - .firstOrNull() + fun findConstructor(classDeclaration: KSClassDeclaration): KSFunctionDeclaration? = + classDeclaration.primaryConstructor?.takeIf { isPublicConstructor(it) } + ?: classDeclaration.getAllFunctions() + .filter { function -> + val simpleName = function.simpleName.asString() + (simpleName == "" || simpleName == classDeclaration.simpleName.asString()) && + isPublicConstructor(function) + } + .maxByOrNull { it.parameters.size } - private fun isPublicConstructor(function: KSFunctionDeclaration): Boolean { - val modifiers = function.modifiers - return !modifiers.contains(Modifier.PRIVATE) && - !modifiers.contains(Modifier.PROTECTED) && - !modifiers.contains(Modifier.INTERNAL) - } + private fun isPublicConstructor(function: KSFunctionDeclaration): Boolean = + function.modifiers.none { it == Modifier.PRIVATE || it == Modifier.PROTECTED || it == Modifier.INTERNAL } } From 2b32e8bbe2bef961442e62c4aef912ae18c6aff8 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 17:27:57 +0100 Subject: [PATCH 086/196] build: remove duplicate `-Xcontext-parameters` argument in compiler options --- alchemist-loading/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-loading/build.gradle.kts b/alchemist-loading/build.gradle.kts index 15c518844b..f2bdf99cca 100644 --- a/alchemist-loading/build.gradle.kts +++ b/alchemist-loading/build.gradle.kts @@ -86,8 +86,8 @@ tasks.withType { compilerOptions { freeCompilerArgs.addAll( "-opt-in=kotlin.time.ExperimentalTime", + "-Xcontext-parameters", ) - freeCompilerArgs.add("-Xcontext-parameters") } } From 179a143d9b2276720f80883875f21247bb2591c3 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 17:30:07 +0100 Subject: [PATCH 087/196] chore: add copyright notice to BoundProcessor.kt --- .../alchemist/boundary/dsl/processor/BoundProcessor.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt index f9ce44b4ed..d33aba8cff 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSTypeArgument From ee503737ae1a76fdde3d055951c03d158057ec21 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 17:30:51 +0100 Subject: [PATCH 088/196] refactor: simplify type argument formatting in BoundProcessor.kt --- .../boundary/dsl/processor/BoundProcessor.kt | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt index d33aba8cff..861be507cc 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt @@ -51,28 +51,21 @@ object BoundProcessor { private fun formatTypeArgument(arg: KSTypeArgument, classTypeParamNames: List): String = when { arg.type == null -> "*" arg.variance == Variance.STAR -> "*" - arg.variance == Variance.CONTRAVARIANT -> { - arg.type?.let { - val typeStr = TypeExtractor.extractTypeString(it, emptyList()) - val replaced = replaceClassTypeParamReferences(typeStr, classTypeParamNames) - "in $replaced" - } ?: "*" - } - arg.variance == Variance.COVARIANT -> { - arg.type?.let { - val typeStr = TypeExtractor.extractTypeString(it, emptyList()) - val replaced = replaceClassTypeParamReferences(typeStr, classTypeParamNames) - "out $replaced" - } ?: "*" - } - else -> { - arg.type?.let { - val typeStr = TypeExtractor.extractTypeString(it, emptyList()) - replaceClassTypeParamReferences(typeStr, classTypeParamNames) - } ?: "*" - } + arg.variance == Variance.CONTRAVARIANT -> arg.transformWithVariance(classTypeParamNames, "in") + arg.variance == Variance.COVARIANT -> arg.transformWithVariance(classTypeParamNames, "out") + else -> arg.transformWithVariance(classTypeParamNames) } + private fun KSTypeArgument.transformWithVariance( + classTypeParamNames: List, + variance: String? = null, + ): String = type?.let { + val typeStr = TypeExtractor.extractTypeString(it, emptyList()) + sequenceOf(variance, replaceClassTypeParamReferences(typeStr, classTypeParamNames)) + .filterNotNull() + .joinToString(" ") + } ?: "*" + private fun replaceClassTypeParamReferences(boundStr: String, classTypeParamNames: List): String { // Strip redundant qualification when the matcher references // the same class-level type parameter From 9803adfc4bf31d9d549f0635e7b1a8af140f94d8 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 17:31:23 +0100 Subject: [PATCH 089/196] chore: remove unnecessary blank line in build.gradle.kts --- alchemist-api/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/alchemist-api/build.gradle.kts b/alchemist-api/build.gradle.kts index 8b9292aa9f..74cf14ebd1 100644 --- a/alchemist-api/build.gradle.kts +++ b/alchemist-api/build.gradle.kts @@ -16,7 +16,6 @@ dependencies { api(libs.jool) api(libs.listset) implementation(libs.kotlin.reflect) - testImplementation(libs.kotlin.test) } From fa1cfe5466af2fbb7bda14c5da63e3154edecd5c Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 17:32:06 +0100 Subject: [PATCH 090/196] chore: remove unused jvm() configuration and test dependencies in build.gradle.kts --- alchemist-dsl-processor/build.gradle.kts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/alchemist-dsl-processor/build.gradle.kts b/alchemist-dsl-processor/build.gradle.kts index f0fa6c349c..9552fe4017 100644 --- a/alchemist-dsl-processor/build.gradle.kts +++ b/alchemist-dsl-processor/build.gradle.kts @@ -5,7 +5,6 @@ plugins { } kotlin { - jvm() sourceSets { val jvmMain by getting { dependencies { @@ -13,11 +12,5 @@ kotlin { implementation(libs.ksp.api) } } - val jvmTest by getting { - dependencies { - implementation(libs.bundles.testing.compile) - runtimeOnly(libs.bundles.testing.runtimeOnly) - } - } } } From f8923e9c95ea3ce52fcae840f2d9e397df71fd0b Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 17:34:03 +0100 Subject: [PATCH 091/196] refactor: streamline logging in DslBuilderProcessor.kt --- .../alchemist/boundary/dsl/processor/DslBuilderProcessor.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index e618388b9d..7608da9a07 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -19,9 +19,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val * Processes every `@AlchemistKotlinDSL` symbol, generating helpers and reporting unresolved ones. */ override fun process(resolver: Resolver): List { - logger.info( - "DslBuilderProcessor: Starting processing", - ) + logger.info("DslBuilderProcessor: Starting processing") logger.info( "DslBuilderProcessor: AlchemistKotlinDSL qualified name: ${AlchemistKotlinDSL::class.qualifiedName}", ) From bdcb64a4b6e8cc5e545b1dc34ed61abe4eb0e3b4 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 18:55:43 +0100 Subject: [PATCH 092/196] style: use orEmpty() --- .../alchemist/boundary/dsl/processor/DslBuilderProcessor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 7608da9a07..8e422aaa77 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -23,7 +23,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger.info( "DslBuilderProcessor: AlchemistKotlinDSL qualified name: ${AlchemistKotlinDSL::class.qualifiedName}", ) - val annotationName = AlchemistKotlinDSL::class.qualifiedName ?: return emptyList() + val annotationName = AlchemistKotlinDSL::class.qualifiedName.orEmpty() val symbols = resolver.getSymbolsWithAnnotation(annotationName) val symbolList = symbols.toList() logger.info("DslBuilderProcessor: Found ${symbolList.size} symbols with @AlchemistKotlinDSL annotation") From dc38124f27ab678c081f0456ebc6497242d11615 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 18:57:13 +0100 Subject: [PATCH 093/196] chore: track the dokka caches --- .../symbol-processing-api/2.3.2.list | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 dokka-cache/com.google.devtools.ksp/symbol-processing-api/2.3.2.list diff --git a/dokka-cache/com.google.devtools.ksp/symbol-processing-api/2.3.2.list b/dokka-cache/com.google.devtools.ksp/symbol-processing-api/2.3.2.list new file mode 100644 index 0000000000..a3c54d253d --- /dev/null +++ b/dokka-cache/com.google.devtools.ksp/symbol-processing-api/2.3.2.list @@ -0,0 +1,8 @@ +$dokka.format:javadoc-v1 +$dokka.linkExtension:html +$dokka.location:com.google.devtools.ksp.processing/Dependencies.Companion///PointingToDeclaration/com/google/devtools/ksp/processing/Dependencies.Companion.html +com.google.devtools.ksp +com.google.devtools.ksp.processing +com.google.devtools.ksp.symbol +com.google.devtools.ksp.visitor + From 4cab178a2f636e436ce2f8ca8d1dcf4b48e989c8 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 19:26:46 +0100 Subject: [PATCH 094/196] fix: split support types to separate files --- .../dsl/processor/ConstructorParamBuilder.kt | 2 + .../dsl/processor/FunctionGenerator.kt | 3 + .../dsl/processor/GenerationContext.kt | 82 ------------------- .../dsl/processor/data/ConstructorInfo.kt | 29 +++++++ .../dsl/processor/data/GenerationContext.kt | 37 +++++++++ .../dsl/processor/data/InjectionContext.kt | 34 ++++++++ .../dsl/processor/data/TypeParameterInfo.kt | 25 ++++++ 7 files changed, 130 insertions(+), 82 deletions(-) delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 15ee5e12bb..544bb0071a 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -2,6 +2,8 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter +import it.unibo.alchemist.boundary.dsl.processor.data.ConstructorInfo +import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext /** Creates expressions for constructor arguments combining injections and call-site values. */ object ConstructorParamBuilder { diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt index 8c1e28edb2..9ce0ea11d8 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt @@ -2,6 +2,9 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter +import it.unibo.alchemist.boundary.dsl.processor.data.ConstructorInfo +import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext +import it.unibo.alchemist.boundary.dsl.processor.data.TypeParameterInfo /** Emits the signature, call site, and accessor for generated DSL helpers. */ object FunctionGenerator { diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt deleted file mode 100644 index 458db1553d..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/GenerationContext.kt +++ /dev/null @@ -1,82 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSValueParameter - -/** - * Captures the type parameter names and bounds needed inside the generated helper. - * - * @property names Generated type parameter identifiers. - * @property bounds Bounds for each generated type parameter. - * @property classTypeParamNames Original class-level type parameter names. - * @property classTypeParamBounds Original class-level type parameter bounds. - */ -data class TypeParameterInfo( - val names: List, - val bounds: List, - val classTypeParamNames: List = names, - val classTypeParamBounds: List = bounds, -) - -/** - * Describes the constructor parameters before and after injection filtering. - * - * @property allParameters All parameters declared on the constructor. - * @property remainingParams Parameters the caller still needs to provide. - * @property paramsToSkip Indexes of injected parameters inside the constructor. - * @property paramNames Names assigned to the remaining parameters. - * @property paramTypes Types of the remaining parameters. - */ -data class ConstructorInfo( - val allParameters: List, - val remainingParams: List, - val paramsToSkip: Set, - val paramNames: List, - val paramTypes: List, -) - -/** - * Represents the injected values and annotation-driven flags available during generation. - * - * @property indices Mapping of injection types to constructor indexes. - * @property paramNames Local names allocated to injected context parameters. - * @property paramTypes Types assigned to injected context parameters. - * @property annotationValues Extracted values from the `@BuildDsl` annotation. - * @property contextType Chosen context enum describing the current execution environment. - * @property hasContextParams Whether the helper defines context receivers. - * @property contextParamName Name of the context parameter used by accessors. - */ -data class InjectionContext( - val indices: Map, - val paramNames: Map, - val paramTypes: Map, - val annotationValues: Map, - val contextType: ContextType, - val hasContextParams: Boolean = false, - val contextParamName: String = "ctx", -) - -/** - * Aggregates everything needed to emit a DSL helper for a specific class. - * - * @property classDecl The declaration being processed. - * @property className Simple name of the target class. - * @property functionName Generated helper function name. - * @property typeParams Type parameter metadata for the helper. - * @property constructorInfo Constructor metadata derived from the declaration. - * @property injectionContext Information about which parameters need injection. - * @property injectedParams List of injected parameter (name,type) pairs. - * @property defaultValues Default values inferred for remaining params. - * @property needsMapEnvironment Whether a `MapEnvironment` import is required. - */ -data class GenerationContext( - val classDecl: KSClassDeclaration, - val className: String, - val functionName: String, - val typeParams: TypeParameterInfo, - val constructorInfo: ConstructorInfo, - val injectionContext: InjectionContext, - val injectedParams: List>, - val defaultValues: List, - val needsMapEnvironment: Boolean, -) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt new file mode 100644 index 0000000000..3e9a2e0c17 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.data + +import com.google.devtools.ksp.symbol.KSValueParameter + +/** + * Describes the constructor parameters before and after injection filtering. + * + * @property allParameters All parameters declared on the constructor. + * @property remainingParams Parameters the caller still needs to provide. + * @property paramsToSkip Indexes of injected parameters inside the constructor. + * @property paramNames Names assigned to the remaining parameters. + * @property paramTypes Types of the remaining parameters. + */ +data class ConstructorInfo( + val allParameters: List, + val remainingParams: List, + val paramsToSkip: Set, + val paramNames: List, + val paramTypes: List, +) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt new file mode 100644 index 0000000000..af31c8d5a7 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.data + +import com.google.devtools.ksp.symbol.KSClassDeclaration + +/** + * Aggregates everything needed to emit a DSL helper for a specific class. + * + * @property classDecl The declaration being processed. + * @property className Simple name of the target class. + * @property functionName Generated helper function name. + * @property typeParams Type parameter metadata for the helper. + * @property constructorInfo Constructor metadata derived from the declaration. + * @property injectionContext Information about which parameters need injection. + * @property injectedParams List of injected parameter (name,type) pairs. + * @property defaultValues Default values inferred for remaining params. + * @property needsMapEnvironment Whether a `MapEnvironment` import is required. + */ +data class GenerationContext( + val classDecl: KSClassDeclaration, + val className: String, + val functionName: String, + val typeParams: TypeParameterInfo, + val constructorInfo: ConstructorInfo, + val injectionContext: InjectionContext, + val injectedParams: List>, + val defaultValues: List, + val needsMapEnvironment: Boolean, +) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt new file mode 100644 index 0000000000..1b29718e57 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.data + +import it.unibo.alchemist.boundary.dsl.processor.ContextType +import it.unibo.alchemist.boundary.dsl.processor.InjectionType + +/** + * Represents the injected values and annotation-driven flags available during generation. + * + * @property indices Mapping of injection types to constructor indexes. + * @property paramNames Local names allocated to injected context parameters. + * @property paramTypes Types assigned to injected context parameters. + * @property annotationValues Extracted values from the `@BuildDsl` annotation. + * @property contextType Chosen context enum describing the current execution environment. + * @property hasContextParams Whether the helper defines context receivers. + * @property contextParamName Name of the context parameter used by accessors. + */ +data class InjectionContext( + val indices: Map, + val paramNames: Map, + val paramTypes: Map, + val annotationValues: Map, + val contextType: ContextType, + val hasContextParams: Boolean = false, + val contextParamName: String = "ctx", +) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt new file mode 100644 index 0000000000..cde86966c8 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.data + +/** + * Captures the type parameter names and bounds needed inside the generated helper. + * + * @property names Generated type parameter identifiers. + * @property bounds Bounds for each generated type parameter. + * @property classTypeParamNames Original class-level type parameter names. + * @property classTypeParamBounds Original class-level type parameter bounds. + */ +data class TypeParameterInfo( + val names: List, + val bounds: List, + val classTypeParamNames: List = names, + val classTypeParamBounds: List = bounds, +) From 6dd95b41aa09c28e15b5eeba89f07aeb10a93275 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 19:28:08 +0100 Subject: [PATCH 095/196] refactor: move InjectionType to a separate data package --- .../dsl/processor/ConstructorParamBuilder.kt | 1 + .../boundary/dsl/processor/ContextAccessor.kt | 2 ++ .../dsl/processor/ParameterInjector.kt | 27 +------------- .../dsl/processor/data/InjectionContext.kt | 1 - .../dsl/processor/data/InjectionType.kt | 36 +++++++++++++++++++ .../dsl/processor/ContextAccessorTest.kt | 1 + .../dsl/processor/ParameterInjectorTest.kt | 1 + 7 files changed, 42 insertions(+), 27 deletions(-) create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 544bb0071a..b0b13e8949 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -4,6 +4,7 @@ import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter import it.unibo.alchemist.boundary.dsl.processor.data.ConstructorInfo import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext +import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType /** Creates expressions for constructor arguments combining injections and call-site values. */ object ConstructorParamBuilder { diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt index aa65637cdb..5b26f7b7cb 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt @@ -1,5 +1,7 @@ package it.unibo.alchemist.boundary.dsl.processor +import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType + /** * Provides accessor paths for injected parameters based on context type. */ diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index 61be008bdb..d4e0e072d2 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -2,32 +2,7 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSValueParameter - -/** - * Types of parameters that can be injected from context. - */ -enum class InjectionType { - /** Environment parameter injection. */ - ENVIRONMENT, - - /** Random generator parameter injection. */ - GENERATOR, - - /** Incarnation parameter injection. */ - INCARNATION, - - /** Node parameter injection. */ - NODE, - - /** Reaction parameter injection. */ - REACTION, - - /** Time distribution parameter injection. */ - TIMEDISTRIBUTION, - - /** Position-based filter parameter injection. */ - FILTER, -} +import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType /** * Information about a parameter injection. diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt index 1b29718e57..ac489e774e 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt @@ -10,7 +10,6 @@ package it.unibo.alchemist.boundary.dsl.processor.data import it.unibo.alchemist.boundary.dsl.processor.ContextType -import it.unibo.alchemist.boundary.dsl.processor.InjectionType /** * Represents the injected values and annotation-driven flags available during generation. diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt new file mode 100644 index 0000000000..8edd511efa --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.data + +/** + * Types of parameters that can be injected from context. + */ +enum class InjectionType { + /** Environment parameter injection. */ + ENVIRONMENT, + + /** Random generator parameter injection. */ + GENERATOR, + + /** Incarnation parameter injection. */ + INCARNATION, + + /** Node parameter injection. */ + NODE, + + /** Reaction parameter injection. */ + REACTION, + + /** Time distribution parameter injection. */ + TIMEDISTRIBUTION, + + /** Position-based filter parameter injection. */ + FILTER, +} diff --git a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt index 05a4f417f4..17b82583df 100644 --- a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt +++ b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt @@ -9,6 +9,7 @@ package it.unibo.alchemist.boundary.dsl.processor +import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test diff --git a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt index a279497e74..4f268483db 100644 --- a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt +++ b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt @@ -1,5 +1,6 @@ package it.unibo.alchemist.boundary.dsl.processor +import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test From f87345eafc65486132afcedc2823d10e201643bd Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 15 Dec 2025 19:57:47 +0100 Subject: [PATCH 096/196] refactor: improve logging and structure in DslBuilderProcessor --- .../dsl/processor/DslBuilderProcessor.kt | 149 ++++++++++-------- 1 file changed, 82 insertions(+), 67 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 8e422aaa77..0bb37b67cc 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -10,81 +10,47 @@ import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSValueParameter import com.google.devtools.ksp.validate import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL +import it.unibo.alchemist.boundary.dsl.processor.data.ConstructorInfo +import it.unibo.alchemist.boundary.dsl.processor.data.GenerationContext +import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext +import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType +import it.unibo.alchemist.boundary.dsl.processor.data.TypeParameterInfo import java.io.PrintWriter import java.nio.charset.StandardCharsets /** Symbol processor that emits DSL helpers for `@AlchemistKotlinDSL` classes. */ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) : SymbolProcessor { + /** - * Processes every `@AlchemistKotlinDSL` symbol, generating helpers and reporting unresolved ones. + * Processes every `@AlchemistKotlinDSL` symbol, + * generating helpers and returning unresolved ones. */ override fun process(resolver: Resolver): List { - logger.info("DslBuilderProcessor: Starting processing") - logger.info( - "DslBuilderProcessor: AlchemistKotlinDSL qualified name: ${AlchemistKotlinDSL::class.qualifiedName}", - ) - val annotationName = AlchemistKotlinDSL::class.qualifiedName.orEmpty() - val symbols = resolver.getSymbolsWithAnnotation(annotationName) - val symbolList = symbols.toList() - logger.info("DslBuilderProcessor: Found ${symbolList.size} symbols with @AlchemistKotlinDSL annotation") - symbolList.forEach { symbol -> - val qualifiedName = when (symbol) { - is KSClassDeclaration -> symbol.qualifiedName?.asString() ?: "unknown" - else -> symbol.toString() - } - logger.info("DslBuilderProcessor: Found symbol: $qualifiedName") + logger.dslInfo("Starting processing") + val annotationName = AlchemistKotlinDSL::class.qualifiedName + check(!annotationName.isNullOrBlank()) { + "The Alchemist Kotlin DSL annotation name is invalid or missing: '$annotationName'" } - val ret = symbolList.filter { !it.validate() }.toList() - symbolList - .filter { it is KSClassDeclaration && it.validate() } - .forEach { classDecl -> - processClass(classDecl as KSClassDeclaration) + logger.dslInfo("Alchemist DSL annotation: $annotationName") + return resolver.getSymbolsWithAnnotation(annotationName) + .onEach { symbol -> + val qualifiedName = when (symbol) { + is KSClassDeclaration -> symbol.qualifiedName?.asString() ?: "unknown" + else -> symbol.toString() + } + logger.dslInfo("Found symbol: $qualifiedName") + } + .fold(emptyList()) { invalidElements, symbol -> + when { + !symbol.validate() -> invalidElements + symbol + else -> { + if (symbol is KSClassDeclaration) { + processClass(symbol) + } + invalidElements + } + } } - return ret - } - - private fun shouldInjectType(injectionType: InjectionType, annotationValues: Map): Boolean = - when (injectionType) { - InjectionType.ENVIRONMENT -> annotationValues["injectEnvironment"] as? Boolean ?: true - InjectionType.GENERATOR -> annotationValues["injectGenerator"] as? Boolean ?: true - InjectionType.INCARNATION -> annotationValues["injectIncarnation"] as? Boolean ?: true - InjectionType.NODE -> annotationValues["injectNode"] as? Boolean ?: true - InjectionType.REACTION -> annotationValues["injectReaction"] as? Boolean ?: true - InjectionType.TIMEDISTRIBUTION -> true - InjectionType.FILTER -> true - } - - private fun processClass(classDecl: KSClassDeclaration) { - logger.info("DslBuilderProcessor: Processing class ${classDecl.simpleName.asString()}") - logger.info("DslBuilderProcessor: Class qualified name: ${classDecl.qualifiedName?.asString()}") - val annotation = classDecl.annotations.firstOrNull { - it.shortName.asString() == "AlchemistKotlinDSL" - } - if (annotation == null) { - logger.warn("Class ${classDecl.simpleName.asString()} has no @AlchemistKotlinDSL annotation") - return - } - val annotationValues = annotation.arguments - .mapNotNull { arg -> arg.name?.asString()?.let { it to arg.value } } - .toMap() - logger.info("DslBuilderProcessor: Annotation values: $annotationValues") - val manualScope = annotationValues["scope"] as? String - logger.info("DslBuilderProcessor: Manual scope from annotation: '$manualScope'") - val functionName = (annotationValues["functionName"] as? String)?.takeIf { it.isNotEmpty() } - ?: classDecl.simpleName.asString().replaceFirstChar { it.lowercaseChar() } - val constructor = ConstructorFinder.findConstructor(classDecl) - if (constructor == null) { - logger.warn("Class ${classDecl.simpleName.asString()} has no usable constructor") - return - } - val parameters = constructor.parameters - logger.info("DslBuilderProcessor: Found constructor with ${parameters.size} parameters") - parameters.forEachIndexed { index, param -> - val typeName = param.type.resolve().declaration.qualifiedName?.asString() ?: "unknown" - logger.info("DslBuilderProcessor: Parameter $index: ${param.name?.asString()} : $typeName") - } - val generationContext = buildGenerationContext(classDecl, functionName, parameters, annotationValues) - writeGeneratedFile(classDecl, generationContext) } // Gather all derived state (injections, type params, constructor metadata) before emitting code. @@ -95,9 +61,9 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val annotationValues: Map, ): GenerationContext { val injectionIndices = ParameterInjector.findInjectionIndices(parameters) - logger.info("DslBuilderProcessor: Injection indices: $injectionIndices") + logger.dslInfo("Injection indices: $injectionIndices") val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - logger.info("DslBuilderProcessor: Determined context type: $contextType") + logger.dslInfo("Determined context type: $contextType") val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues, contextType) val remainingParams = parameters.filterIndexed { index, _ -> !paramsToSkip.contains(index) } val (initialTypeParamNames, initialTypeParamBounds) = TypeExtractor.extractTypeParameters(classDecl) @@ -162,6 +128,51 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val needsMapEnvironment = needsMapEnvironment, ) } + + private fun shouldInjectType(injectionType: InjectionType, annotationValues: Map): Boolean = + when (injectionType) { + InjectionType.ENVIRONMENT -> annotationValues["injectEnvironment"] as? Boolean ?: true + InjectionType.GENERATOR -> annotationValues["injectGenerator"] as? Boolean ?: true + InjectionType.INCARNATION -> annotationValues["injectIncarnation"] as? Boolean ?: true + InjectionType.NODE -> annotationValues["injectNode"] as? Boolean ?: true + InjectionType.REACTION -> annotationValues["injectReaction"] as? Boolean ?: true + InjectionType.TIMEDISTRIBUTION -> true + InjectionType.FILTER -> true + } + + private fun processClass(classDecl: KSClassDeclaration) { + logger.dslInfo("Processing class ${classDecl.simpleName.asString()}") + logger.dslInfo("Class qualified name: ${classDecl.qualifiedName?.asString()}") + val annotation = classDecl.annotations.firstOrNull { + it.shortName.asString() == "AlchemistKotlinDSL" + } + if (annotation == null) { + logger.warn("Class ${classDecl.simpleName.asString()} has no @AlchemistKotlinDSL annotation") + return + } + val annotationValues = annotation.arguments + .mapNotNull { arg -> arg.name?.asString()?.let { it to arg.value } } + .toMap() + logger.dslInfo("Annotation values: $annotationValues") + val manualScope = annotationValues["scope"] as? String + logger.dslInfo("Manual scope from annotation: '$manualScope'") + val functionName = (annotationValues["functionName"] as? String)?.takeIf { it.isNotEmpty() } + ?: classDecl.simpleName.asString().replaceFirstChar { it.lowercaseChar() } + val constructor = ConstructorFinder.findConstructor(classDecl) + if (constructor == null) { + logger.warn("Class ${classDecl.simpleName.asString()} has no usable constructor") + return + } + val parameters = constructor.parameters + logger.dslInfo("Found constructor with ${parameters.size} parameters") + parameters.forEachIndexed { index, param -> + val typeName = param.type.resolve().declaration.qualifiedName?.asString() ?: "unknown" + logger.dslInfo("Parameter $index: ${param.name?.asString()} : $typeName") + } + val generationContext = buildGenerationContext(classDecl, functionName, parameters, annotationValues) + writeGeneratedFile(classDecl, generationContext) + } + private fun writeGeneratedFile(classDecl: KSClassDeclaration, context: GenerationContext) { val containingFile = classDecl.containingFile val dependencies = if (containingFile != null) { @@ -433,4 +444,8 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val ) writer.println(" $constructorCall") } + + companion object { + private fun KSPLogger.dslInfo(message: String) = info("${DslBuilderProcessor::class.simpleName}: $message") + } } From d1dd0823c8f9524a7380309fa1c63cc5c08cb3a7 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 18 Dec 2025 17:50:20 +0100 Subject: [PATCH 097/196] refactor: refactor the Kotlin DSL generator --- .../boundary/dsl/processor/BoundProcessor.kt | 90 ------------------- .../dsl/processor/ConstructorFinder.kt | 31 ------- .../dsl/processor/DslBuilderProcessor.kt | 9 +- .../boundary/dsl/processor/ImportManager.kt | 14 +-- .../dsl/processor/TypeArgumentProcessor.kt | 4 +- .../dsl/processor/TypeBoundProcessor.kt | 60 +++++++++++++ .../boundary/dsl/processor/TypeExtractor.kt | 42 +-------- .../extensions/KSClassDeclaration.kt | 23 +++++ .../dsl/processor/extensions/KSDeclaration.kt | 15 ++++ .../processor/extensions/KSTypeArgument.kt | 31 +++++++ .../processor/extensions/KSTypeExtensions.kt | 18 ++++ alchemist-full/build.gradle.kts | 2 +- 12 files changed, 157 insertions(+), 182 deletions(-) delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclaration.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclaration.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgument.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt deleted file mode 100644 index 861be507cc..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/BoundProcessor.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSTypeArgument -import com.google.devtools.ksp.symbol.KSTypeReference -import com.google.devtools.ksp.symbol.Variance - -/** - * Processes type bounds for type parameters, cleaning up internal Kotlin type representations. - */ -object BoundProcessor { - /** - * Processes a type bound reference, cleaning up internal Kotlin type representations and variance annotations. - * - * @param bound The type reference to process - * @param classTypeParamNames List of class type parameter names to replace in the bound - * @return A cleaned string representation of the bound with fully qualified names - */ - fun processBound(bound: KSTypeReference, classTypeParamNames: List = emptyList()): String { - val resolved = bound.resolve() - val decl = resolved.declaration - val qualifiedName = decl.qualifiedName?.asString() - if (qualifiedName != null) { - val arguments = resolved.arguments - val typeString = if (arguments.isNotEmpty()) { - val typeArgs = arguments.joinToString(", ") { arg -> - formatTypeArgument(arg, classTypeParamNames) - } - "$qualifiedName<$typeArgs>" - } else { - qualifiedName - } - val nullableSuffix = if (resolved.isMarkedNullable) "?" else "" - val result = "$typeString$nullableSuffix" - return replaceClassTypeParamReferences(result, classTypeParamNames) - } - val result = TypeExtractor.extractTypeString(bound, emptyList()) - return replaceClassTypeParamReferences(result, classTypeParamNames) - } - - // Bring each type argument back into a printable form, - // handling variance explicitly. - private fun formatTypeArgument(arg: KSTypeArgument, classTypeParamNames: List): String = when { - arg.type == null -> "*" - arg.variance == Variance.STAR -> "*" - arg.variance == Variance.CONTRAVARIANT -> arg.transformWithVariance(classTypeParamNames, "in") - arg.variance == Variance.COVARIANT -> arg.transformWithVariance(classTypeParamNames, "out") - else -> arg.transformWithVariance(classTypeParamNames) - } - - private fun KSTypeArgument.transformWithVariance( - classTypeParamNames: List, - variance: String? = null, - ): String = type?.let { - val typeStr = TypeExtractor.extractTypeString(it, emptyList()) - sequenceOf(variance, replaceClassTypeParamReferences(typeStr, classTypeParamNames)) - .filterNotNull() - .joinToString(" ") - } ?: "*" - - private fun replaceClassTypeParamReferences(boundStr: String, classTypeParamNames: List): String { - // Strip redundant qualification when the matcher references - // the same class-level type parameter - if (classTypeParamNames.isEmpty()) { - return boundStr - } - var result = boundStr - classTypeParamNames.forEach { paramName -> - val pattern = Regex("""\b[\w.]+\.$paramName\b""") - result = pattern.replace(result) { matchResult -> - val matched = matchResult.value - val prefix = matched.substringBefore(".$paramName") - if (prefix.contains(".")) { - paramName - } else { - matched - } - } - } - return result - } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt deleted file mode 100644 index d675256ede..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorFinder.kt +++ /dev/null @@ -1,31 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import com.google.devtools.ksp.symbol.Modifier - -/** - * Finds a suitable constructor for a class declaration. - */ -object ConstructorFinder { - /** - * Finds a public constructor for the given class declaration. - * Prefers the primary constructor, otherwise returns the constructor - * with the most parameters. - * - * @param classDeclaration The class declaration to find a constructor for - * @return The found constructor, or null if no suitable constructor exists - */ - fun findConstructor(classDeclaration: KSClassDeclaration): KSFunctionDeclaration? = - classDeclaration.primaryConstructor?.takeIf { isPublicConstructor(it) } - ?: classDeclaration.getAllFunctions() - .filter { function -> - val simpleName = function.simpleName.asString() - (simpleName == "" || simpleName == classDeclaration.simpleName.asString()) && - isPublicConstructor(function) - } - .maxByOrNull { it.parameters.size } - - private fun isPublicConstructor(function: KSFunctionDeclaration): Boolean = - function.modifiers.none { it == Modifier.PRIVATE || it == Modifier.PROTECTED || it == Modifier.INTERNAL } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 0bb37b67cc..d439ffb6ad 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -9,6 +9,7 @@ import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSValueParameter import com.google.devtools.ksp.validate +import findConstructor import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.boundary.dsl.processor.data.ConstructorInfo import it.unibo.alchemist.boundary.dsl.processor.data.GenerationContext @@ -158,7 +159,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger.dslInfo("Manual scope from annotation: '$manualScope'") val functionName = (annotationValues["functionName"] as? String)?.takeIf { it.isNotEmpty() } ?: classDecl.simpleName.asString().replaceFirstChar { it.lowercaseChar() } - val constructor = ConstructorFinder.findConstructor(classDecl) + val constructor = classDecl.findConstructor() if (constructor == null) { logger.warn("Class ${classDecl.simpleName.asString()} has no usable constructor") return @@ -375,11 +376,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val ImportManager.writeImports( writer, context.typeParams.bounds, - context.constructorInfo.paramTypes, - context.defaultValues, context.classDecl, - context.needsMapEnvironment, - context.injectionContext.paramTypes.values.toList(), ) val constructorParams = FunctionGenerator.buildConstructorParams( context.constructorInfo, @@ -445,7 +442,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val writer.println(" $constructorCall") } - companion object { + private companion object { private fun KSPLogger.dslInfo(message: String) = info("${DslBuilderProcessor::class.simpleName}: $message") } } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt index 504506ac5a..d9fbdcbc49 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt @@ -11,22 +11,10 @@ object ImportManager { * Writes all necessary import statements to the generated code file. * * @param writer The PrintWriter to write imports to - * @param typeParamBounds Type parameter bounds that may require imports - * @param paramTypes Parameter types that may require imports * @param defaultValues Default value expressions that may require imports * @param classDecl The class declaration being processed - * @param needsMapEnvironment Whether MapEnvironment import is needed - * @param injectedParamTypes Types of injected parameters that may require imports */ - fun writeImports( - writer: PrintWriter, - @Suppress("UNUSED_PARAMETER") typeParamBounds: List, - @Suppress("UNUSED_PARAMETER") paramTypes: List, - defaultValues: List, - classDecl: KSClassDeclaration, - @Suppress("UNUSED_PARAMETER") needsMapEnvironment: Boolean = false, - @Suppress("UNUSED_PARAMETER") injectedParamTypes: List = emptyList(), - ) { + fun writeImports(writer: PrintWriter, defaultValues: List, classDecl: KSClassDeclaration) { val neededImports = DefaultValueAnalyzer.extractNeededImportsFromDefaults(defaultValues, classDecl) neededImports.forEach { writer.println(it) } writer.println() diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt index ad0a87b40e..6fb5a9b394 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt @@ -123,7 +123,7 @@ object TypeArgumentProcessor { typeParamNames.add(paramName) val boundStr = if (declParam != null) { val bounds = declParam.bounds.map { bound -> - BoundProcessor.processBound(bound) + TypeBoundProcessor.processBound(bound) }.toList() if (bounds.isNotEmpty()) { "$paramName: ${bounds.joinToString(" & ")}" @@ -163,7 +163,7 @@ object TypeArgumentProcessor { val paramName = argDecl.name.asString() if (!typeParamNames.contains(paramName)) { typeParamNames.add(paramName) - val bounds = argDecl.bounds.map { BoundProcessor.processBound(it) }.toList() + val bounds = argDecl.bounds.map { TypeBoundProcessor.processBound(it) }.toList() val boundStr = if (bounds.isNotEmpty()) { "$paramName: ${bounds.joinToString(" & ")}" } else { diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt new file mode 100644 index 0000000000..545b41c1f6 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.symbol.KSTypeReference +import it.unibo.alchemist.boundary.dsl.processor.extensions.toStringWithGenerics + +/** + * Processes type bounds for type parameters, cleaning up internal Kotlin type representations. + */ +object TypeBoundProcessor { + /** + * Processes a type bound reference, cleaning up internal Kotlin type representations and variance annotations. + * + * @param bound The type reference to process + * @param classTypeParamNames List of class type parameter names to replace in the bound + * @return A cleaned string representation of the bound with fully qualified names + */ + fun processBound(bound: KSTypeReference, classTypeParamNames: List = emptyList()): String { + val resolved = bound.resolve() + val decl = resolved.declaration + val qualifiedName = decl.qualifiedName?.asString() + if (qualifiedName != null) { + val result = resolved.toStringWithGenerics(classTypeParamNames) + return replaceClassTypeParamReferences(result, classTypeParamNames) + } + val result = TypeExtractor.extractTypeString(bound, emptyList()) + return replaceClassTypeParamReferences(result, classTypeParamNames) + } +} + +// TODO: revise this function +internal fun replaceClassTypeParamReferences(boundStr: String, classTypeParamNames: List): String { + // Strip redundant qualification when the matcher references + // the same class-level type parameter + if (classTypeParamNames.isEmpty()) { + return boundStr + } + var result = boundStr + classTypeParamNames.forEach { paramName -> + val pattern = Regex("""\b[\w.]+\.$paramName\b""") + result = pattern.replace(result) { matchResult -> + val matched = matchResult.value + val prefix = matched.substringBefore(".$paramName") + if (prefix.contains(".")) { + paramName + } else { + matched + } + } + } + return result +} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt index b8fed31cc4..fa4c5cb891 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt @@ -1,12 +1,10 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSDeclaration -import com.google.devtools.ksp.symbol.KSTypeArgument import com.google.devtools.ksp.symbol.KSTypeParameter import com.google.devtools.ksp.symbol.KSTypeReference import com.google.devtools.ksp.symbol.KSValueParameter -import com.google.devtools.ksp.symbol.Variance +import it.unibo.alchemist.boundary.dsl.processor.extensions.toStringWithGenerics /** * Extracts type information from KSP symbols for code generation. @@ -23,7 +21,7 @@ object TypeExtractor { val typeParamNames = typeParameters.map { it.name.asString() } val typeParamBounds = typeParameters.map { typeParam -> val bounds: List = typeParam.bounds.map { bound -> - BoundProcessor.processBound(bound, typeParamNames) + TypeBoundProcessor.processBound(bound, typeParamNames) }.toList() if (bounds.isNotEmpty()) { val boundStr = bounds.joinToString(" & ") @@ -52,41 +50,7 @@ object TypeExtractor { return paramName } } - val typeName = getTypeName(declaration) - val arguments = resolved.arguments - val typeString = if (arguments.isNotEmpty()) { - val typeArgs = arguments.joinToString(", ") { arg -> - formatTypeArgument(arg, typeParamNames) - } - "$typeName<$typeArgs>" - } else { - typeName - } - return if (resolved.isMarkedNullable) { - "$typeString?" - } else { - typeString - } - } - - private fun getTypeName(declaration: KSDeclaration): String { - val qualifiedName = declaration.qualifiedName?.asString() - return if (qualifiedName != null && qualifiedName.isNotEmpty()) { - qualifiedName - } else { - declaration.simpleName.asString() - } - } - - // Represent the variance and nested references for each argument. - private fun formatTypeArgument(arg: KSTypeArgument, typeParamNames: List): String = when { - arg.type == null -> "*" - arg.variance == Variance.STAR -> "*" - arg.variance == Variance.CONTRAVARIANT -> - arg.type?.let { "in ${extractTypeString(it, typeParamNames)}" } ?: "*" - arg.variance == Variance.COVARIANT -> - arg.type?.let { "out ${extractTypeString(it, typeParamNames)}" } ?: "*" - else -> arg.type?.let { extractTypeString(it, typeParamNames) } ?: "*" + return resolved.toStringWithGenerics(typeParamNames) } /** diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclaration.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclaration.kt new file mode 100644 index 0000000000..e6914aecd2 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclaration.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +import com.google.devtools.ksp.isPublic +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSFunctionDeclaration + +/** + * Finds a public constructor for the given class declaration. + * Prefers the primary constructor, otherwise returns the constructor + * with the most parameters. + * + * @return The found constructor, or null if no suitable constructor exists + */ +internal fun KSClassDeclaration.findConstructor(): KSFunctionDeclaration? = primaryConstructor?.takeIf { it.isPublic() } + ?: getAllFunctions() + .filter { it.isPublic() && it.simpleName.asString() in listOf("", simpleName.asString()) } + .maxByOrNull { it.parameters.size } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclaration.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclaration.kt new file mode 100644 index 0000000000..8dfe02e767 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclaration.kt @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.extensions + +import com.google.devtools.ksp.symbol.KSDeclaration + +internal val KSDeclaration.typeName: String + get() = qualifiedName?.asString()?.takeIf { it.isNotEmpty() } ?: simpleName.asString() diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgument.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgument.kt new file mode 100644 index 0000000000..467e7e6722 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgument.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.extensions + +import com.google.devtools.ksp.symbol.KSTypeArgument +import com.google.devtools.ksp.symbol.Variance +import it.unibo.alchemist.boundary.dsl.processor.TypeExtractor +import it.unibo.alchemist.boundary.dsl.processor.replaceClassTypeParamReferences + +internal fun KSTypeArgument.format(typeParameterNames: List): String = when { + type == null -> "*" + variance == Variance.STAR -> "*" + variance == Variance.CONTRAVARIANT -> transformWithVariance(typeParameterNames, "in") + variance == Variance.COVARIANT -> transformWithVariance(typeParameterNames, "out") + else -> transformWithVariance(typeParameterNames) +} + +private fun KSTypeArgument.transformWithVariance(typeParameterNames: List, variance: String? = null): String = + type?.let { + val typeStr = TypeExtractor.extractTypeString(it, emptyList()) + sequenceOf(variance, replaceClassTypeParamReferences(typeStr, typeParameterNames)) + .filterNotNull() + .joinToString(" ") + } ?: "*" diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt new file mode 100644 index 0000000000..ef6dea04ff --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.extensions + +import com.google.devtools.ksp.symbol.KSType + +internal fun KSType.toStringWithGenerics(typeParamNames: List): String = "${declaration.typeName}${ + arguments.takeIf { it.isNotEmpty() } + ?.joinToString(prefix = "<", separator = ", ", postfix = ">") { it.format(typeParamNames) } + .orEmpty() +}${"?".takeIf { isMarkedNullable }.orEmpty()}" diff --git a/alchemist-full/build.gradle.kts b/alchemist-full/build.gradle.kts index b29372d13d..1a032774ce 100644 --- a/alchemist-full/build.gradle.kts +++ b/alchemist-full/build.gradle.kts @@ -280,7 +280,7 @@ val packageTasks = validFormats.filterIsInstance().map { packagi tasks.assemble.configure { dependsOn(packageTasks) } tasks.withType { - duplicatesStrategy = DuplicatesStrategy.WARN + duplicatesStrategy = DuplicatesStrategy.INCLUDE } publishing.publications { From bb9b693255c8e0b31cfbfb45e5216d454e7b34a4 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 18 Dec 2025 18:20:47 +0100 Subject: [PATCH 098/196] refactor: enhance context handling in DslBuilderProcessor and ParameterInjector --- .../dsl/processor/DslBuilderProcessor.kt | 46 ++++++++++--------- .../dsl/processor/ParameterInjector.kt | 21 ++++----- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index d439ffb6ad..6c427c7d24 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -27,34 +27,37 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val * generating helpers and returning unresolved ones. */ override fun process(resolver: Resolver): List { - logger.dslInfo("Starting processing") - val annotationName = AlchemistKotlinDSL::class.qualifiedName - check(!annotationName.isNullOrBlank()) { - "The Alchemist Kotlin DSL annotation name is invalid or missing: '$annotationName'" - } - logger.dslInfo("Alchemist DSL annotation: $annotationName") - return resolver.getSymbolsWithAnnotation(annotationName) - .onEach { symbol -> - val qualifiedName = when (symbol) { - is KSClassDeclaration -> symbol.qualifiedName?.asString() ?: "unknown" - else -> symbol.toString() - } - logger.dslInfo("Found symbol: $qualifiedName") + context(resolver) { + logger.dslInfo("Starting processing") + val annotationName = AlchemistKotlinDSL::class.qualifiedName + check(!annotationName.isNullOrBlank()) { + "The Alchemist Kotlin DSL annotation name is invalid or missing: '$annotationName'" } - .fold(emptyList()) { invalidElements, symbol -> - when { - !symbol.validate() -> invalidElements + symbol - else -> { - if (symbol is KSClassDeclaration) { - processClass(symbol) + logger.dslInfo("Alchemist DSL annotation: $annotationName") + return resolver.getSymbolsWithAnnotation(annotationName) + .onEach { symbol -> + val qualifiedName = when (symbol) { + is KSClassDeclaration -> symbol.qualifiedName?.asString() ?: "unknown" + else -> symbol.toString() + } + logger.dslInfo("Found symbol: $qualifiedName") + } + .fold(emptyList()) { invalidElements, symbol -> + when { + !symbol.validate() -> invalidElements + symbol + else -> { + if (symbol is KSClassDeclaration) { + processClass(symbol) + } + invalidElements } - invalidElements } } - } + } } // Gather all derived state (injections, type params, constructor metadata) before emitting code. + context(resolver: Resolver) private fun buildGenerationContext( classDecl: KSClassDeclaration, functionName: String, @@ -141,6 +144,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val InjectionType.FILTER -> true } + context(resolver: Resolver) private fun processClass(classDecl: KSClassDeclaration) { logger.dslInfo("Processing class ${classDecl.simpleName.asString()}") logger.dslInfo("Class qualified name: ${classDecl.qualifiedName?.asString()}") diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index d4e0e072d2..2b768a07ea 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -1,8 +1,11 @@ package it.unibo.alchemist.boundary.dsl.processor +import com.google.devtools.ksp.getClassDeclarationByName +import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSValueParameter import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType +import it.unibo.alchemist.model.TimeDistribution /** * Information about a parameter injection. @@ -30,7 +33,8 @@ object ParameterInjector { * @param parameters The list of constructor parameters to analyze * @return A map from injection type to parameter index */ - fun findInjectionIndices(parameters: List): Map { + context(resolver: Resolver) + internal fun findInjectionIndices(parameters: List): Map { val indices = mutableMapOf() parameters.forEachIndexed { index, param -> val resolved = param.type.resolve() @@ -43,8 +47,7 @@ object ParameterInjector { isIncarnationType(resolved, qualifiedName) -> indices[InjectionType.INCARNATION] = index isNodeType(resolved, simpleName, qualifiedName) -> indices[InjectionType.NODE] = index isReactionType(resolved, simpleName, qualifiedName) -> indices[InjectionType.REACTION] = index - isTimeDistributionType(resolved, simpleName, qualifiedName) -> - indices[InjectionType.TIMEDISTRIBUTION] = index + isTimeDistribution(resolved) -> indices[InjectionType.TIMEDISTRIBUTION] = index isFilterType(resolved, simpleName, qualifiedName) -> indices[InjectionType.FILTER] = index } } @@ -96,14 +99,10 @@ object ParameterInjector { qualifiedName.startsWith("${ProcessorConfig.REACTION_TYPE}.") } - private fun isTimeDistributionType(type: KSType, simpleName: String, qualifiedName: String): Boolean { - if (simpleName != "TimeDistribution" && !qualifiedName.endsWith(".TimeDistribution")) { - return false - } - return TypeHierarchyChecker.isAssignableTo(type, ProcessorConfig.TIME_DISTRIBUTION_TYPE) || - qualifiedName == ProcessorConfig.TIME_DISTRIBUTION_TYPE || - qualifiedName.startsWith("${ProcessorConfig.TIME_DISTRIBUTION_TYPE}.") - } + context(resolver: Resolver) + private fun isTimeDistribution(type: KSType): Boolean = + checkNotNull(resolver.getClassDeclarationByName>()) + .asStarProjectedType().isAssignableFrom(type) private fun isFilterType(type: KSType, simpleName: String, qualifiedName: String): Boolean { val effectiveType = type.makeNotNullable() From bfd3effa18e099b559b3f32fab4b925f4c375340 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 18 Dec 2025 18:28:31 +0100 Subject: [PATCH 099/196] refactor: extract ContextType enum to a new file for better organization --- .../boundary/dsl/processor/ContextType.kt | 42 +++++++++++++++++++ .../dsl/processor/ParameterInjector.kt | 39 ++--------------- 2 files changed, 45 insertions(+), 36 deletions(-) create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt new file mode 100644 index 0000000000..8c9e1bde88 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor + +/** + * Type of context available for parameter injection. + */ +enum class ContextType { + /** Simulation context (only incarnation or only environment). */ + SIMULATION_CONTEXT, + + /** Exporter context (one level below SimulationContext, manually settable). */ + EXPORTER_CONTEXT, + + /** Global programs context (one level below SimulationContext, manually settable). */ + GLOBAL_PROGRAMS_CONTEXT, + + /** Output monitors context (one level below SimulationContext, manually settable). */ + OUTPUT_MONITORS_CONTEXT, + + /** Terminators context (one level below SimulationContext, manually settable). */ + TERMINATORS_CONTEXT, + + /** Deployments context (generator). */ + DEPLOYMENTS_CONTEXT, + + /** Deployment context (singular, one level below DeploymentsContext, includes filter). */ + DEPLOYMENT_CONTEXT, + + /** Program context (includes node, reaction, and time distribution). */ + PROGRAM_CONTEXT, + + /** Property context (includes node, same depth as program context). */ + PROPERTY_CONTEXT, +} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index 2b768a07ea..1c24d755f2 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -47,7 +47,7 @@ object ParameterInjector { isIncarnationType(resolved, qualifiedName) -> indices[InjectionType.INCARNATION] = index isNodeType(resolved, simpleName, qualifiedName) -> indices[InjectionType.NODE] = index isReactionType(resolved, simpleName, qualifiedName) -> indices[InjectionType.REACTION] = index - isTimeDistribution(resolved) -> indices[InjectionType.TIMEDISTRIBUTION] = index + resolved.isSubtypeOf>() -> indices[InjectionType.TIMEDISTRIBUTION] = index isFilterType(resolved, simpleName, qualifiedName) -> indices[InjectionType.FILTER] = index } } @@ -100,9 +100,8 @@ object ParameterInjector { } context(resolver: Resolver) - private fun isTimeDistribution(type: KSType): Boolean = - checkNotNull(resolver.getClassDeclarationByName>()) - .asStarProjectedType().isAssignableFrom(type) + private inline fun KSType.isSubtypeOf(): Boolean = + checkNotNull(resolver.getClassDeclarationByName()).asStarProjectedType().isAssignableFrom(this) private fun isFilterType(type: KSType, simpleName: String, qualifiedName: String): Boolean { val effectiveType = type.makeNotNullable() @@ -306,35 +305,3 @@ object ParameterInjector { } } } - -/** - * Type of context available for parameter injection. - */ -enum class ContextType { - /** Simulation context (only incarnation or only environment). */ - SIMULATION_CONTEXT, - - /** Exporter context (one level below SimulationContext, manually settable). */ - EXPORTER_CONTEXT, - - /** Global programs context (one level below SimulationContext, manually settable). */ - GLOBAL_PROGRAMS_CONTEXT, - - /** Output monitors context (one level below SimulationContext, manually settable). */ - OUTPUT_MONITORS_CONTEXT, - - /** Terminators context (one level below SimulationContext, manually settable). */ - TERMINATORS_CONTEXT, - - /** Deployments context (generator). */ - DEPLOYMENTS_CONTEXT, - - /** Deployment context (singular, one level below DeploymentsContext, includes filter). */ - DEPLOYMENT_CONTEXT, - - /** Program context (includes node, reaction, and time distribution). */ - PROGRAM_CONTEXT, - - /** Property context (includes node, same depth as program context). */ - PROPERTY_CONTEXT, -} From 2ed2287e9e9f1941cc109ce797e77985629d7ba4 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 18 Dec 2025 18:48:07 +0100 Subject: [PATCH 100/196] refactor: simplify type checks in ParameterInjector by using isSubtypeOf --- .../dsl/processor/ParameterInjector.kt | 60 ++++--------------- 1 file changed, 10 insertions(+), 50 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index 1c24d755f2..872ced3686 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -5,7 +5,12 @@ import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSValueParameter import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Reaction import it.unibo.alchemist.model.TimeDistribution +import org.apache.commons.math3.random.RandomGenerator /** * Information about a parameter injection. @@ -42,11 +47,11 @@ object ParameterInjector { val qualifiedName = declaration.qualifiedName?.asString().orEmpty() val simpleName = declaration.simpleName.asString() when { - isEnvironmentType(resolved, qualifiedName) -> indices[InjectionType.ENVIRONMENT] = index - isGeneratorType(resolved, qualifiedName) -> indices[InjectionType.GENERATOR] = index - isIncarnationType(resolved, qualifiedName) -> indices[InjectionType.INCARNATION] = index - isNodeType(resolved, simpleName, qualifiedName) -> indices[InjectionType.NODE] = index - isReactionType(resolved, simpleName, qualifiedName) -> indices[InjectionType.REACTION] = index + resolved.isSubtypeOf>() -> indices[InjectionType.ENVIRONMENT] = index + resolved.isSubtypeOf() -> indices[InjectionType.GENERATOR] = index + resolved.isSubtypeOf>() -> indices[InjectionType.INCARNATION] = index + resolved.isSubtypeOf>() -> indices[InjectionType.NODE] = index + resolved.isSubtypeOf>() -> indices[InjectionType.REACTION] = index resolved.isSubtypeOf>() -> indices[InjectionType.TIMEDISTRIBUTION] = index isFilterType(resolved, simpleName, qualifiedName) -> indices[InjectionType.FILTER] = index } @@ -54,51 +59,6 @@ object ParameterInjector { return indices } - private fun isEnvironmentType(type: KSType, qualifiedName: String): Boolean { - if (!qualifiedName.contains("Environment")) { - return false - } - return TypeHierarchyChecker.matchesTypeOrPackage( - type, - ProcessorConfig.ENVIRONMENT_TYPE, - ProcessorConfig.ENVIRONMENT_PACKAGE_PATTERNS, - ) - } - - private fun isGeneratorType(type: KSType, qualifiedName: String): Boolean { - if (!qualifiedName.contains("RandomGenerator")) { - return false - } - return TypeHierarchyChecker.isAssignableTo(type, ProcessorConfig.RANDOM_GENERATOR_TYPE) || - qualifiedName == ProcessorConfig.RANDOM_GENERATOR_TYPE - } - - private fun isIncarnationType(type: KSType, qualifiedName: String): Boolean { - if (!qualifiedName.contains("Incarnation")) { - return false - } - return TypeHierarchyChecker.isAssignableTo(type, ProcessorConfig.INCARNATION_TYPE) || - qualifiedName == ProcessorConfig.INCARNATION_TYPE - } - - private fun isNodeType(type: KSType, simpleName: String, qualifiedName: String): Boolean { - if (simpleName != "Node" && !qualifiedName.endsWith(".Node")) { - return false - } - return TypeHierarchyChecker.isAssignableTo(type, ProcessorConfig.NODE_TYPE) || - qualifiedName == ProcessorConfig.NODE_TYPE || - qualifiedName.startsWith("${ProcessorConfig.NODE_TYPE}.") - } - - private fun isReactionType(type: KSType, simpleName: String, qualifiedName: String): Boolean { - if (simpleName != "Reaction" && !qualifiedName.endsWith(".Reaction")) { - return false - } - return TypeHierarchyChecker.isAssignableTo(type, ProcessorConfig.REACTION_TYPE) || - qualifiedName == ProcessorConfig.REACTION_TYPE || - qualifiedName.startsWith("${ProcessorConfig.REACTION_TYPE}.") - } - context(resolver: Resolver) private inline fun KSType.isSubtypeOf(): Boolean = checkNotNull(resolver.getClassDeclarationByName()).asStarProjectedType().isAssignableFrom(this) From ddaf97da9be545af1903ec57851b0461fcb035cb Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 18 Dec 2025 18:48:57 +0100 Subject: [PATCH 101/196] refactor: simplify manual scope check in ParameterInjector --- .../unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index 872ced3686..5a331bd6c0 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -123,7 +123,7 @@ object ParameterInjector { annotationValues: Map, ): ContextType { val manualScope = annotationValues["scope"] as? String - if (manualScope != null && manualScope.isNotBlank()) { + if (!manualScope.isNullOrBlank()) { val parsedScope = parseScope(manualScope) if (parsedScope != null) { return parsedScope From 569d80f5ca5bfe9e58a0beb6759a5ee404dcd1ef Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 18 Dec 2025 18:58:21 +0100 Subject: [PATCH 102/196] refactor: make ProcessorConfig internal and remove unused type constants and methods --- .../boundary/dsl/processor/ProcessorConfig.kt | 53 +------------------ .../dsl/processor/ProcessorConfigTest.kt | 26 --------- 2 files changed, 1 insertion(+), 78 deletions(-) delete mode 100644 alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt index 64b3194104..20e0672163 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt @@ -4,7 +4,7 @@ package it.unibo.alchemist.boundary.dsl.processor * Configuration for the DSL processor, centralizing package names and type detection rules. * This makes the processor more maintainable and allows for easier customization. */ -object ProcessorConfig { +internal object ProcessorConfig { /** * Base package for Alchemist model classes. */ @@ -30,51 +30,11 @@ object ProcessorConfig { */ const val POSITION_TYPE = "$MODEL_PACKAGE.Position" - /** - * Fully qualified name for the Environment interface. - */ - const val ENVIRONMENT_TYPE = "$MODEL_PACKAGE.Environment" - - /** - * Fully qualified name for the Incarnation interface. - */ - const val INCARNATION_TYPE = "$MODEL_PACKAGE.Incarnation" - - /** - * Fully qualified name for the Node class. - */ - const val NODE_TYPE = "$MODEL_PACKAGE.Node" - - /** - * Fully qualified name for the Reaction interface. - */ - const val REACTION_TYPE = "$MODEL_PACKAGE.Reaction" - - /** - * Fully qualified name for the TimeDistribution interface. - */ - const val TIME_DISTRIBUTION_TYPE = "$MODEL_PACKAGE.TimeDistribution" - /** * Fully qualified name for PositionBasedFilter interface. */ const val POSITION_BASED_FILTER_TYPE = "$MODEL_PACKAGE.PositionBasedFilter" - /** - * Fully qualified name for RandomGenerator. - */ - const val RANDOM_GENERATOR_TYPE = "org.apache.commons.math3.random.RandomGenerator" - - /** - * Package patterns that should be considered for Environment type detection. - * This replaces the hardcoded "maps" check. - */ - val ENVIRONMENT_PACKAGE_PATTERNS = setOf( - MODEL_PACKAGE, - "$MODEL_PACKAGE.maps", - "$MODEL_PACKAGE.environments", - ) - /** * Context type class names. */ @@ -112,15 +72,4 @@ object ProcessorConfig { /** Fully qualified name for PropertyContext. */ const val PROPERTY_CONTEXT = "$DSL_MODEL_PACKAGE.PropertyContext" } - - /** - * Checks if a qualified name matches any of the environment package patterns. - * - * @param qualifiedName The fully qualified name to check - * @return True if the name matches an environment package pattern - */ - // Provide centralized patterns instead of ad-hoc string checks so injector stays flexible. - fun isEnvironmentPackage(qualifiedName: String): Boolean = ENVIRONMENT_PACKAGE_PATTERNS.any { pattern -> - qualifiedName.startsWith(pattern) - } } diff --git a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt deleted file mode 100644 index c17fc5346c..0000000000 --- a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfigTest.kt +++ /dev/null @@ -1,26 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test - -class ProcessorConfigTest { - @Test - fun `test environment package patterns`() { - assertTrue(ProcessorConfig.isEnvironmentPackage("it.unibo.alchemist.model.Environment")) - assertTrue(ProcessorConfig.isEnvironmentPackage("it.unibo.alchemist.model.maps.OSMEnvironment")) - assertTrue( - ProcessorConfig.isEnvironmentPackage("it.unibo.alchemist.model.environments.Continuous2DEnvironment"), - ) - assertTrue(!ProcessorConfig.isEnvironmentPackage("com.example.Environment")) - } - - @Test - fun `test config constants`() { - assertEquals("it.unibo.alchemist.model", ProcessorConfig.MODEL_PACKAGE) - assertEquals("it.unibo.alchemist.boundary.dsl", ProcessorConfig.DSL_PACKAGE) - assertEquals("it.unibo.alchemist.boundary.dsl.generated", ProcessorConfig.GENERATED_PACKAGE) - assertEquals("it.unibo.alchemist.model.Position", ProcessorConfig.POSITION_TYPE) - assertEquals("it.unibo.alchemist.model.Environment", ProcessorConfig.ENVIRONMENT_TYPE) - } -} From 95c6f82733b01f1cb442e9868dfe2d6ddbd57dbd Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 18 Dec 2025 18:58:55 +0100 Subject: [PATCH 103/196] refactor: remove redundant logging of found symbols in DslBuilderProcessor --- .../boundary/dsl/processor/DslBuilderProcessor.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 6c427c7d24..800c05c05d 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -35,13 +35,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val } logger.dslInfo("Alchemist DSL annotation: $annotationName") return resolver.getSymbolsWithAnnotation(annotationName) - .onEach { symbol -> - val qualifiedName = when (symbol) { - is KSClassDeclaration -> symbol.qualifiedName?.asString() ?: "unknown" - else -> symbol.toString() - } - logger.dslInfo("Found symbol: $qualifiedName") - } .fold(emptyList()) { invalidElements, symbol -> when { !symbol.validate() -> invalidElements + symbol From 2568f410b1d00c54fc7794e8939f254949fc066d Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 18 Dec 2025 19:33:25 +0100 Subject: [PATCH 104/196] refactor: simplify AlchemistKotlinDSL annotation and remove unused parameters --- .../boundary/dsl/AlchemistKotlinDSL.kt | 28 +-- .../dsl/processor/ConstructorParamBuilder.kt | 10 +- .../dsl/processor/DslBuilderProcessor.kt | 79 ++----- .../dsl/processor/ParameterInjector.kt | 73 ++----- .../dsl/processor/TypeArgumentProcessor.kt | 2 +- .../dsl/processor/data/InjectionContext.kt | 2 - .../dsl/processor/ParameterInjectorTest.kt | 193 +----------------- 7 files changed, 46 insertions(+), 341 deletions(-) diff --git a/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt b/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt index 62c63a9930..7f66c8492a 100644 --- a/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt +++ b/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt @@ -13,33 +13,7 @@ package it.unibo.alchemist.boundary.dsl * Annotation used to mark classes that should have DSL builder functions generated. * When applied to a class, the DSL processor will generate a builder function * that can be used in Alchemist DSL scripts to create instances of the annotated class. - * - * @param functionName Custom name for the generated DSL function. If empty, defaults to - * the lowercase version of the class name with the first character lowercased. - * @param scope Manual override for the context type. Valid values (case-insensitive): - * - "SIMULATION" or "SIMULATION_CONTEXT" → SimulationContext - * - "EXPORTER" or "EXPORTER_CONTEXT" → ExporterContext - * - "GLOBAL_PROGRAMS" or "GLOBAL_PROGRAMS_CONTEXT" → GlobalProgramsContext - * - "OUTPUT_MONITORS" or "OUTPUT_MONITORS_CONTEXT" → OutputMonitorsContext - * - "TERMINATORS" or "TERMINATORS_CONTEXT" → TerminatorsContext - * - "DEPLOYMENT" or "DEPLOYMENTS_CONTEXT" → DeploymentsContext - * - "DEPLOYMENT_CONTEXT" → DeploymentContext (singular) - * - "PROGRAM" or "PROGRAM_CONTEXT" → ProgramContext - * - "PROPERTY" or "PROPERTY_CONTEXT" → PropertyContext - * If empty, the context type is automatically determined based on the constructor parameters. - * This allows manual context passing to override the default behavior. - * @param injectEnvironment Whether to inject an Environment parameter into the generated builder function. - * @param injectGenerator Whether to inject a Generator parameter into the generated builder function. - * @param injectNode Whether to inject a Node parameter into the generated builder function. - * @param injectReaction Whether to inject a Reaction parameter into the generated builder function. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.SOURCE) -annotation class AlchemistKotlinDSL( - val functionName: String = "", - val scope: String = "", - val injectEnvironment: Boolean = true, - val injectGenerator: Boolean = true, - val injectNode: Boolean = true, - val injectReaction: Boolean = true, -) +annotation class AlchemistKotlinDSL diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index b0b13e8949..2687907214 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -26,11 +26,7 @@ object ConstructorParamBuilder { injectionType: InjectionType, index: Int, injectionIndices: Map, - annotationValues: Map, - annotationKey: String, - ): Boolean = injectionIndices.containsKey(injectionType) && - index == injectionIndices[injectionType] && - annotationValues[annotationKey] as? Boolean ?: true + ): Boolean = injectionIndices.containsKey(injectionType) && index == injectionIndices[injectionType] private fun buildInjectedParam( injectionType: InjectionType, @@ -220,14 +216,12 @@ object ConstructorParamBuilder { paramsToSkip: Set, injectionTypes: List>, ): InjectionType? { - for ((type, annotationKey, checkAnnotation) in injectionTypes) { + for ((type, _, checkAnnotation) in injectionTypes) { val matchesAnnotation = checkAnnotation && isInjectionIndex( type, index, injectionContext.indices, - injectionContext.annotationValues, - annotationKey, ) val matchesFallback = !checkAnnotation && matchesFallbackInjection( index, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 800c05c05d..199dea11a3 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -55,13 +55,12 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val classDecl: KSClassDeclaration, functionName: String, parameters: List, - annotationValues: Map, ): GenerationContext { val injectionIndices = ParameterInjector.findInjectionIndices(parameters) logger.dslInfo("Injection indices: $injectionIndices") - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) + val contextType = ParameterInjector.determineContextType(injectionIndices) logger.dslInfo("Determined context type: $contextType") - val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, annotationValues, contextType) + val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, contextType) val remainingParams = parameters.filterIndexed { index, _ -> !paramsToSkip.contains(index) } val (initialTypeParamNames, initialTypeParamBounds) = TypeExtractor.extractTypeParameters(classDecl) val typeParamNames = initialTypeParamNames.toMutableList() @@ -74,7 +73,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val val (injectedParams, injectedParamNames, injectedParamTypesMap) = processInjectedParams( injectionIndices, - annotationValues, parameters, typeParamNames, typeParamBounds, @@ -83,7 +81,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val updateTypeParamsForInjected( hasInjectedParams, injectionIndices, - annotationValues, parameters, typeParamNames, typeParamBounds, @@ -108,7 +105,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val indices = injectionIndices, paramNames = injectedParamNames, paramTypes = injectedParamTypesMap, - annotationValues = annotationValues, contextType = contextType, hasContextParams = hasInjectedParams, contextParamName = "ctx", @@ -126,36 +122,11 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val ) } - private fun shouldInjectType(injectionType: InjectionType, annotationValues: Map): Boolean = - when (injectionType) { - InjectionType.ENVIRONMENT -> annotationValues["injectEnvironment"] as? Boolean ?: true - InjectionType.GENERATOR -> annotationValues["injectGenerator"] as? Boolean ?: true - InjectionType.INCARNATION -> annotationValues["injectIncarnation"] as? Boolean ?: true - InjectionType.NODE -> annotationValues["injectNode"] as? Boolean ?: true - InjectionType.REACTION -> annotationValues["injectReaction"] as? Boolean ?: true - InjectionType.TIMEDISTRIBUTION -> true - InjectionType.FILTER -> true - } - context(resolver: Resolver) private fun processClass(classDecl: KSClassDeclaration) { logger.dslInfo("Processing class ${classDecl.simpleName.asString()}") logger.dslInfo("Class qualified name: ${classDecl.qualifiedName?.asString()}") - val annotation = classDecl.annotations.firstOrNull { - it.shortName.asString() == "AlchemistKotlinDSL" - } - if (annotation == null) { - logger.warn("Class ${classDecl.simpleName.asString()} has no @AlchemistKotlinDSL annotation") - return - } - val annotationValues = annotation.arguments - .mapNotNull { arg -> arg.name?.asString()?.let { it to arg.value } } - .toMap() - logger.dslInfo("Annotation values: $annotationValues") - val manualScope = annotationValues["scope"] as? String - logger.dslInfo("Manual scope from annotation: '$manualScope'") - val functionName = (annotationValues["functionName"] as? String)?.takeIf { it.isNotEmpty() } - ?: classDecl.simpleName.asString().replaceFirstChar { it.lowercaseChar() } + val functionName = classDecl.simpleName.asString().replaceFirstChar { it.lowercaseChar() } val constructor = classDecl.findConstructor() if (constructor == null) { logger.warn("Class ${classDecl.simpleName.asString()} has no usable constructor") @@ -167,7 +138,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val val typeName = param.type.resolve().declaration.qualifiedName?.asString() ?: "unknown" logger.dslInfo("Parameter $index: ${param.name?.asString()} : $typeName") } - val generationContext = buildGenerationContext(classDecl, functionName, parameters, annotationValues) + val generationContext = buildGenerationContext(classDecl, functionName, parameters) writeGeneratedFile(classDecl, generationContext) } @@ -192,10 +163,8 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val private fun writeGeneratedCode(writer: PrintWriter, context: GenerationContext) { writeFileHeader(writer, context.classDecl, context.injectionContext.contextType) val constructorParams = writeImportsAndFunction(writer, context) - val hasNode = context.injectionContext.indices.containsKey(InjectionType.NODE) && - context.injectionContext.annotationValues["injectNode"] as? Boolean ?: true - val hasReaction = context.injectionContext.indices.containsKey(InjectionType.REACTION) && - context.injectionContext.annotationValues["injectReaction"] as? Boolean ?: true + val hasNode = context.injectionContext.indices.containsKey(InjectionType.NODE) + val hasReaction = context.injectionContext.indices.containsKey(InjectionType.REACTION) if (hasNode && !hasReaction) { writePropertyContextFunction(writer, context, constructorParams) } @@ -260,7 +229,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val private fun processInjectedParams( injectionIndices: Map, - annotationValues: Map, allParameters: List, typeParamNames: MutableList, typeParamBounds: MutableList, @@ -269,14 +237,12 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val val injectedParamNames = mutableMapOf() val injectedParamTypesMap = mutableMapOf() injectionIndices.forEach { (injectionType, index) -> - if (shouldInjectType(injectionType, annotationValues)) { - val param = allParameters[index] - val paramType = FunctionGenerator.buildContextParamType(param.type, typeParamNames, typeParamBounds) - val paramName = getInjectionParamName(injectionType) - injectedParams.add(paramName to paramType) - injectedParamNames[injectionType] = paramName - injectedParamTypesMap[injectionType] = paramType - } + val param = allParameters[index] + val paramType = FunctionGenerator.buildContextParamType(param.type, typeParamNames, typeParamBounds) + val paramName = getInjectionParamName(injectionType) + injectedParams.add(paramName to paramType) + injectedParamNames[injectionType] = paramName + injectedParamTypesMap[injectionType] = paramType } return Triple(injectedParams, injectedParamNames, injectedParamTypesMap) } @@ -294,7 +260,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val private fun updateTypeParamsForInjected( hasInjectedParams: Boolean, injectionIndices: Map, - annotationValues: Map, allParameters: List, typeParamNames: MutableList, typeParamBounds: MutableList, @@ -305,18 +270,16 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val return } val newTypeParams = mutableMapOf() - injectionIndices.forEach { (injectionType, index) -> - if (shouldInjectType(injectionType, annotationValues)) { - val param = allParameters[index] - val initialSize = typeParamNames.size - FunctionGenerator.buildContextParamType(param.type, typeParamNames, typeParamBounds) + injectionIndices.forEach { (_, index) -> + val param = allParameters[index] + val initialSize = typeParamNames.size + FunctionGenerator.buildContextParamType(param.type, typeParamNames, typeParamBounds) - for (i in initialSize until typeParamNames.size) { - val newParam = typeParamNames[i] - val newBound = typeParamBounds[i] - if (!newTypeParams.containsKey(newParam)) { - newTypeParams[newParam] = newBound - } + for (i in initialSize until typeParamNames.size) { + val newParam = typeParamNames[i] + val newBound = typeParamBounds[i] + if (!newTypeParams.containsKey(newParam)) { + newTypeParams[newParam] = newBound } } } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index 5a331bd6c0..87b8e7a4cc 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -114,55 +114,29 @@ object ParameterInjector { * If a manual scope is provided in the annotation, it takes precedence over automatic detection. * * @param injectionIndices Map of injection types to parameter indices - * @param annotationValues Annotation values from the AlchemistKotlinDSL annotation * @return The determined context type */ // Determine which context is active by checking manual overrides first, then injection mix. - fun determineContextType( - injectionIndices: Map, - annotationValues: Map, - ): ContextType { - val manualScope = annotationValues["scope"] as? String - if (!manualScope.isNullOrBlank()) { - val parsedScope = parseScope(manualScope) - if (parsedScope != null) { - return parsedScope - } - } - return determineContextTypeFromInjections(injectionIndices, annotationValues) - } + fun determineContextType(injectionIndices: Map): ContextType = + determineContextTypeFromInjections(injectionIndices) - private fun determineContextTypeFromInjections( - injectionIndices: Map, - annotationValues: Map, - ): ContextType = when { + private fun determineContextTypeFromInjections(injectionIndices: Map): ContextType = when { injectionIndices.containsKey(InjectionType.FILTER) -> ContextType.DEPLOYMENT_CONTEXT - hasProgramContextInjections(injectionIndices, annotationValues) -> ContextType.PROGRAM_CONTEXT - else -> determineDeploymentOrSimulationContext(injectionIndices, annotationValues) + hasProgramContextInjections(injectionIndices) -> ContextType.PROGRAM_CONTEXT + else -> determineDeploymentOrSimulationContext(injectionIndices) } - private fun hasProgramContextInjections( - injectionIndices: Map, - annotationValues: Map, - ): Boolean { - val hasNode = injectionIndices.containsKey(InjectionType.NODE) && - annotationValues["injectNode"] as? Boolean ?: true - val hasReaction = injectionIndices.containsKey(InjectionType.REACTION) && - annotationValues["injectReaction"] as? Boolean ?: true + private fun hasProgramContextInjections(injectionIndices: Map): Boolean { + val hasNode = injectionIndices.containsKey(InjectionType.NODE) + val hasReaction = injectionIndices.containsKey(InjectionType.REACTION) val hasTimeDistribution = injectionIndices.containsKey(InjectionType.TIMEDISTRIBUTION) return hasNode || hasReaction || hasTimeDistribution } - private fun determineDeploymentOrSimulationContext( - injectionIndices: Map, - annotationValues: Map, - ): ContextType { - val hasEnvironment = injectionIndices.containsKey(InjectionType.ENVIRONMENT) && - annotationValues["injectEnvironment"] as? Boolean ?: true - val hasGenerator = injectionIndices.containsKey(InjectionType.GENERATOR) && - annotationValues["injectGenerator"] as? Boolean ?: true - val hasIncarnation = injectionIndices.containsKey(InjectionType.INCARNATION) && - annotationValues["injectIncarnation"] as? Boolean ?: true + private fun determineDeploymentOrSimulationContext(injectionIndices: Map): ContextType { + val hasEnvironment = injectionIndices.containsKey(InjectionType.ENVIRONMENT) + val hasGenerator = injectionIndices.containsKey(InjectionType.GENERATOR) + val hasIncarnation = injectionIndices.containsKey(InjectionType.INCARNATION) val injectedCount = listOf(hasEnvironment, hasGenerator, hasIncarnation).count { it } return if (injectedCount == 1 && (hasIncarnation || hasEnvironment)) { ContextType.SIMULATION_CONTEXT @@ -175,22 +149,15 @@ object ParameterInjector { * Gets the set of parameter indices that should be skipped (injected from context). * * @param injectionIndices Map of injection types to parameter indices - * @param annotationValues Annotation values from the AlchemistKotlinDSL annotation * @param contextType The context type to determine which parameters can be injected * @return Set of parameter indices to skip */ - fun getInjectionParams( - injectionIndices: Map, - annotationValues: Map, - contextType: ContextType, - ): Set { + fun getInjectionParams(injectionIndices: Map, contextType: ContextType): Set { val paramsToSkip = mutableSetOf() if (isInjectionTypeAvailable(InjectionType.ENVIRONMENT, contextType)) { addInjectionParamIfEnabled( InjectionType.ENVIRONMENT, - "injectEnvironment", injectionIndices, - annotationValues, paramsToSkip, ) } @@ -198,9 +165,7 @@ object ParameterInjector { if (isInjectionTypeAvailable(InjectionType.GENERATOR, contextType)) { addInjectionParamIfEnabled( InjectionType.GENERATOR, - "injectGenerator", injectionIndices, - annotationValues, paramsToSkip, ) } @@ -208,9 +173,7 @@ object ParameterInjector { if (isInjectionTypeAvailable(InjectionType.INCARNATION, contextType)) { addInjectionParamIfEnabled( InjectionType.INCARNATION, - "injectIncarnation", injectionIndices, - annotationValues, paramsToSkip, ) } @@ -218,9 +181,7 @@ object ParameterInjector { if (isInjectionTypeAvailable(InjectionType.NODE, contextType)) { addInjectionParamIfEnabled( InjectionType.NODE, - "injectNode", injectionIndices, - annotationValues, paramsToSkip, ) } @@ -228,9 +189,7 @@ object ParameterInjector { if (isInjectionTypeAvailable(InjectionType.REACTION, contextType)) { addInjectionParamIfEnabled( InjectionType.REACTION, - "injectReaction", injectionIndices, - annotationValues, paramsToSkip, ) } @@ -253,14 +212,10 @@ object ParameterInjector { private fun addInjectionParamIfEnabled( injectionType: InjectionType, - annotationKey: String, injectionIndices: Map, - annotationValues: Map, paramsToSkip: MutableSet, ) { - if (annotationValues[annotationKey] as? Boolean ?: true && - injectionIndices.containsKey(injectionType) - ) { + if (injectionIndices.containsKey(injectionType)) { injectionIndices[injectionType]?.let { paramsToSkip.add(it) } } } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt index 6fb5a9b394..5b27b96ff3 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt @@ -54,7 +54,7 @@ object TypeArgumentProcessor { private fun getTypeName(declaration: KSDeclaration): String { val qualifiedName = declaration.qualifiedName?.asString() - return if (qualifiedName != null && qualifiedName.isNotEmpty()) { + return if (!qualifiedName.isNullOrEmpty()) { qualifiedName } else { declaration.simpleName.asString() diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt index ac489e774e..15567c4510 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt @@ -17,7 +17,6 @@ import it.unibo.alchemist.boundary.dsl.processor.ContextType * @property indices Mapping of injection types to constructor indexes. * @property paramNames Local names allocated to injected context parameters. * @property paramTypes Types assigned to injected context parameters. - * @property annotationValues Extracted values from the `@BuildDsl` annotation. * @property contextType Chosen context enum describing the current execution environment. * @property hasContextParams Whether the helper defines context receivers. * @property contextParamName Name of the context parameter used by accessors. @@ -26,7 +25,6 @@ data class InjectionContext( val indices: Map, val paramNames: Map, val paramTypes: Map, - val annotationValues: Map, val contextType: ContextType, val hasContextParams: Boolean = false, val contextParamName: String = "ctx", diff --git a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt index 4f268483db..80063a5e9b 100644 --- a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt +++ b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt @@ -1,7 +1,7 @@ package it.unibo.alchemist.boundary.dsl.processor import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType -import org.junit.jupiter.api.Assertions.assertEquals +import kotlin.test.assertEquals import org.junit.jupiter.api.Test class ParameterInjectorTest { @@ -11,10 +11,7 @@ class ParameterInjectorTest { InjectionType.NODE to 0, InjectionType.REACTION to 1, ) - val annotationValues = emptyMap() - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - + val contextType = ParameterInjector.determineContextType(injectionIndices) assertEquals(ContextType.PROGRAM_CONTEXT, contextType) } @@ -23,10 +20,7 @@ class ParameterInjectorTest { val injectionIndices = mapOf( InjectionType.ENVIRONMENT to 0, ) - val annotationValues = emptyMap() - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - + val contextType = ParameterInjector.determineContextType(injectionIndices) assertEquals(ContextType.SIMULATION_CONTEXT, contextType) } @@ -35,10 +29,7 @@ class ParameterInjectorTest { val injectionIndices = mapOf( InjectionType.INCARNATION to 0, ) - val annotationValues = emptyMap() - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - + val contextType = ParameterInjector.determineContextType(injectionIndices) assertEquals(ContextType.SIMULATION_CONTEXT, contextType) } @@ -48,10 +39,7 @@ class ParameterInjectorTest { InjectionType.ENVIRONMENT to 0, InjectionType.GENERATOR to 1, ) - val annotationValues = emptyMap() - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - + val contextType = ParameterInjector.determineContextType(injectionIndices) assertEquals(ContextType.DEPLOYMENTS_CONTEXT, contextType) } @@ -62,47 +50,22 @@ class ParameterInjectorTest { InjectionType.GENERATOR to 1, InjectionType.NODE to 2, ) - val annotationValues = emptyMap() - val paramsToSkip = ParameterInjector.getInjectionParams( injectionIndices, - annotationValues, ContextType.PROGRAM_CONTEXT, ) - assertEquals(setOf(0, 1, 2), paramsToSkip) } - @Test - fun `test getInjectionParams with environment disabled`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - InjectionType.GENERATOR to 1, - ) - val annotationValues = mapOf("injectEnvironment" to false) - - val paramsToSkip = ParameterInjector.getInjectionParams( - injectionIndices, - annotationValues, - ContextType.DEPLOYMENTS_CONTEXT, - ) - - assertEquals(setOf(1), paramsToSkip) - } - @Test fun `test getInjectionParams with time distribution always injected`() { val injectionIndices = mapOf( InjectionType.TIMEDISTRIBUTION to 0, ) - val annotationValues = emptyMap() - val paramsToSkip = ParameterInjector.getInjectionParams( injectionIndices, - annotationValues, ContextType.PROGRAM_CONTEXT, ) - assertEquals(setOf(0), paramsToSkip) } @@ -112,172 +75,30 @@ class ParameterInjectorTest { InjectionType.ENVIRONMENT to 0, InjectionType.TIMEDISTRIBUTION to 1, ) - val annotationValues = emptyMap() - val paramsToSkip = ParameterInjector.getInjectionParams( injectionIndices, - annotationValues, ContextType.GLOBAL_PROGRAMS_CONTEXT, ) assertEquals(setOf(0), paramsToSkip) } - @Test - fun `test determineContextType with manual scope PROGRAM override`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val annotationValues = mapOf("scope" to "PROGRAM") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.PROGRAM_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with manual scope SIMULATION override`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - InjectionType.GENERATOR to 1, - ) - val annotationValues = mapOf("scope" to "SIMULATION") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.SIMULATION_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with manual scope DEPLOYMENT override`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val annotationValues = mapOf("scope" to "DEPLOYMENT") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.DEPLOYMENTS_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with manual scope DEPLOYMENTS_CONTEXT override`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val annotationValues = mapOf("scope" to "DEPLOYMENTS_CONTEXT") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.DEPLOYMENTS_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with manual scope PROPERTY override`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val annotationValues = mapOf("scope" to "PROPERTY") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.PROPERTY_CONTEXT, contextType) - } - @Test fun `test determineContextType with filter parameter`() { val injectionIndices = mapOf( InjectionType.ENVIRONMENT to 0, InjectionType.FILTER to 1, ) - val annotationValues = emptyMap() - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - + val contextType = ParameterInjector.determineContextType(injectionIndices) assertEquals(ContextType.DEPLOYMENT_CONTEXT, contextType) } - @Test - fun `test determineContextType with filter and manual scope override`() { - val injectionIndices = mapOf( - InjectionType.FILTER to 0, - ) - val annotationValues = mapOf("scope" to "PROGRAM") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.PROGRAM_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with manual scope EXPORTER_CONTEXT override`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val annotationValues = mapOf("scope" to "EXPORTER_CONTEXT") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.EXPORTER_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with manual scope GLOBAL_PROGRAMS_CONTEXT override`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val annotationValues = mapOf("scope" to "GLOBAL_PROGRAMS_CONTEXT") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.GLOBAL_PROGRAMS_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with manual scope OUTPUT_MONITORS_CONTEXT override`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val annotationValues = mapOf("scope" to "OUTPUT_MONITORS_CONTEXT") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.OUTPUT_MONITORS_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with manual scope TERMINATORS_CONTEXT override`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val annotationValues = mapOf("scope" to "TERMINATORS_CONTEXT") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.TERMINATORS_CONTEXT, contextType) - } - @Test fun `test determineContextType with invalid scope falls back to automatic detection`() { val injectionIndices = mapOf( InjectionType.ENVIRONMENT to 0, ) - val annotationValues = mapOf("scope" to "INVALID_SCOPE") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - - assertEquals(ContextType.SIMULATION_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with empty scope falls back to automatic detection`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val annotationValues = mapOf("scope" to "") - - val contextType = ParameterInjector.determineContextType(injectionIndices, annotationValues) - + val contextType = ParameterInjector.determineContextType(injectionIndices) assertEquals(ContextType.SIMULATION_CONTEXT, contextType) } From 5b5326dbf3a3516f96c928c4635b5c559fb6f3db Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 19 Dec 2025 12:47:47 +0100 Subject: [PATCH 105/196] marmellata --- .../dsl/processor/DslBuilderProcessor.kt | 59 ++++++++++++++++--- ...ion.kt => KSClassDeclarationExtensions.kt} | 0 ...laration.kt => KSDeclarationExtensions.kt} | 0 .../KSFunctionDeclarationExtensions.kt | 19 ++++++ ...rgument.kt => KSTypeArgumentExtensions.kt} | 0 ...sions.kt => KSTypeExtensionsExtensions.kt} | 0 6 files changed, 70 insertions(+), 8 deletions(-) rename alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/{KSClassDeclaration.kt => KSClassDeclarationExtensions.kt} (100%) rename alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/{KSDeclaration.kt => KSDeclarationExtensions.kt} (100%) create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt rename alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/{KSTypeArgument.kt => KSTypeArgumentExtensions.kt} (100%) rename alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/{KSTypeExtensions.kt => KSTypeExtensionsExtensions.kt} (100%) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 199dea11a3..29e25f752a 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -1,5 +1,8 @@ package it.unibo.alchemist.boundary.dsl.processor +import com.google.devtools.ksp.getClassDeclarationByName +import com.google.devtools.ksp.getConstructors +import com.google.devtools.ksp.isPublic import com.google.devtools.ksp.processing.CodeGenerator import com.google.devtools.ksp.processing.Dependencies import com.google.devtools.ksp.processing.KSPLogger @@ -7,6 +10,7 @@ import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.processing.SymbolProcessor import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSValueParameter import com.google.devtools.ksp.validate import findConstructor @@ -16,8 +20,16 @@ import it.unibo.alchemist.boundary.dsl.processor.data.GenerationContext import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType import it.unibo.alchemist.boundary.dsl.processor.data.TypeParameterInfo +import it.unibo.alchemist.core.Simulation +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.LinkingRule +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Reaction +import it.unibo.alchemist.model.TimeDistribution import java.io.PrintWriter import java.nio.charset.StandardCharsets +import parameterTypes /** Symbol processor that emits DSL helpers for `@AlchemistKotlinDSL` classes. */ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) : SymbolProcessor { @@ -123,13 +135,31 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val } context(resolver: Resolver) - private fun processClass(classDecl: KSClassDeclaration) { - logger.dslInfo("Processing class ${classDecl.simpleName.asString()}") - logger.dslInfo("Class qualified name: ${classDecl.qualifiedName?.asString()}") - val functionName = classDecl.simpleName.asString().replaceFirstChar { it.lowercaseChar() } - val constructor = classDecl.findConstructor() + private fun processClass(classDeclaration: KSClassDeclaration) { + logger.dslInfo("Processing class ${classDeclaration.simpleName.asString()}") + logger.dslInfo("Class qualified name: ${classDeclaration.qualifiedName?.asString()}") + val injectableTypes = injectableTypes() + val contextualizableConstructors = classDeclaration.getConstructors() + .filter { it.isPublic() } + .map { it to it.parameterTypes } + .filter { (_, parameterTypes) -> + // Only consider constructors with injectable parameters + parameterTypes.any { it in injectableTypes } + } + .distinctBy { (_, parameterTypes) -> parameterTypes - injectableTypes } + .map { it.first } + .toSet() + val file = codeGenerator.createNewFile( + dependencies = classDeclaration.containingFile + ?.let { Dependencies(false, it) } + ?: Dependencies.ALL_FILES, + packageName = classDeclaration.packageName.asString(), + fileName = "", + ) + val functionName = classDeclaration.simpleName.asString().replaceFirstChar { it.lowercaseChar() } + val constructor = classDeclaration.findConstructor() if (constructor == null) { - logger.warn("Class ${classDecl.simpleName.asString()} has no usable constructor") + logger.warn("Class ${classDeclaration.simpleName.asString()} has no usable constructor") return } val parameters = constructor.parameters @@ -138,8 +168,8 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val val typeName = param.type.resolve().declaration.qualifiedName?.asString() ?: "unknown" logger.dslInfo("Parameter $index: ${param.name?.asString()} : $typeName") } - val generationContext = buildGenerationContext(classDecl, functionName, parameters) - writeGeneratedFile(classDecl, generationContext) + val generationContext = buildGenerationContext(classDeclaration, functionName, parameters) + writeGeneratedFile(classDeclaration, generationContext) } private fun writeGeneratedFile(classDecl: KSClassDeclaration, context: GenerationContext) { @@ -404,5 +434,18 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val private companion object { private fun KSPLogger.dslInfo(message: String) = info("${DslBuilderProcessor::class.simpleName}: $message") + + context(resolver: Resolver) + fun injectableTypes(): Set = sequenceOf( + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + ) + .map { checkNotNull(it).asStarProjectedType() } + .toSet() } } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclaration.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclarationExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclaration.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclarationExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclaration.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclarationExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclaration.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclarationExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt new file mode 100644 index 0000000000..8e3d6c8b70 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import com.google.devtools.ksp.symbol.KSType + +/** + * Finds a public constructor for the given class declaration. + * Prefers the primary constructor, otherwise returns the constructor + * with the most parameters. + * + * @return The found constructor, or null if no suitable constructor exists + */ +internal val KSFunctionDeclaration.parameterTypes: List get() = parameters.map { it.type.resolve() } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgument.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgument.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensionsExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensionsExtensions.kt From abc47f7e738eacd7637fc6be2e64aec1d9569e37 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 22 Dec 2025 19:44:32 +0100 Subject: [PATCH 106/196] marmellata --- .../dsl/processor/DslBuilderProcessor.kt | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 29e25f752a..32c60b4d8c 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -63,7 +63,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val // Gather all derived state (injections, type params, constructor metadata) before emitting code. context(resolver: Resolver) - private fun buildGenerationContext( + fun buildGenerationContext( classDecl: KSClassDeclaration, functionName: String, parameters: List, @@ -139,6 +139,17 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger.dslInfo("Processing class ${classDeclaration.simpleName.asString()}") logger.dslInfo("Class qualified name: ${classDeclaration.qualifiedName?.asString()}") val injectableTypes = injectableTypes() + val file = codeGenerator.createNewFile( + dependencies = classDeclaration.containingFile + ?.let { Dependencies(false, it) } + ?: Dependencies.ALL_FILES, + packageName = classDeclaration.packageName.asString(), + fileName = "${classDeclaration.simpleName.asString()}Factory.kt", + ) + val writer = PrintWriter(file, true, StandardCharsets.UTF_8) + writer.println("// This file is generated by Alchemist DSL Processor. Do not edit manually.") + writer.println() + writer.println("package ${classDeclaration.packageName.asString()}") val contextualizableConstructors = classDeclaration.getConstructors() .filter { it.isPublic() } .map { it to it.parameterTypes } @@ -149,14 +160,25 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val .distinctBy { (_, parameterTypes) -> parameterTypes - injectableTypes } .map { it.first } .toSet() - val file = codeGenerator.createNewFile( - dependencies = classDeclaration.containingFile - ?.let { Dependencies(false, it) } - ?: Dependencies.ALL_FILES, - packageName = classDeclaration.packageName.asString(), - fileName = "", - ) val functionName = classDeclaration.simpleName.asString().replaceFirstChar { it.lowercaseChar() } + contextualizableConstructors.forEach { constructor -> + val typeParameters = constructor.typeParameters + .takeIf { it.isNotEmpty() } + ?.joinToString(prefix = "<", postfix = ">") { + buildString { + if (it.isReified) { + append("reified ") + } + append(it.name.asString()) + } + } + .orEmpty() + writer.println( + """ + inline fun $typeParameters $functionName() = TODO() + """.trimIndent(), + ) + } val constructor = classDeclaration.findConstructor() if (constructor == null) { logger.warn("Class ${classDeclaration.simpleName.asString()} has no usable constructor") @@ -168,11 +190,11 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val val typeName = param.type.resolve().declaration.qualifiedName?.asString() ?: "unknown" logger.dslInfo("Parameter $index: ${param.name?.asString()} : $typeName") } - val generationContext = buildGenerationContext(classDeclaration, functionName, parameters) - writeGeneratedFile(classDeclaration, generationContext) +// val generationContext = buildGenerationContext(classDeclaration, functionName, parameters) +// writeGeneratedFile(classDeclaration, generationContext) } - private fun writeGeneratedFile(classDecl: KSClassDeclaration, context: GenerationContext) { + fun writeGeneratedFile(classDecl: KSClassDeclaration, context: GenerationContext) { val containingFile = classDecl.containingFile val dependencies = if (containingFile != null) { Dependencies(true, containingFile) From 5d48407908f4ff2b525d66773a77e943d7bb36a8 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Tue, 23 Dec 2025 16:37:39 +0100 Subject: [PATCH 107/196] feat!: rewrite the code generator --- .../dsl/processor/ConstructorParamBuilder.kt | 2 +- .../boundary/dsl/processor/ContextAccessor.kt | 2 +- .../boundary/dsl/processor/ContextType.kt | 2 +- .../dsl/processor/DefaultValueAnalyzer.kt | 2 +- .../dsl/processor/DslBuilderProcessor.kt | 430 +++--------------- .../dsl/processor/FunctionGenerator.kt | 2 +- .../boundary/dsl/processor/ImportManager.kt | 2 +- .../dsl/processor/ParameterInjector.kt | 4 +- .../dsl/processor/TypeArgumentProcessor.kt | 2 +- .../dsl/processor/TypeBoundProcessor.kt | 2 +- .../boundary/dsl/processor/TypeExtractor.kt | 2 +- .../dsl/processor/TypeHierarchyChecker.kt | 2 +- .../dsl/processor/TypeParameterHandler.kt | 2 +- .../dsl/processor/data/ConstructorInfo.kt | 2 +- .../dsl/processor/data/GenerationContext.kt | 2 +- .../processor/data/InjectableConstructor.kt | 35 ++ .../dsl/processor/data/InjectionContext.kt | 2 +- .../dsl/processor/data/InjectionType.kt | 2 +- .../dsl/processor/data/TypeParameterInfo.kt | 2 +- .../KSFunctionDeclarationExtensions.kt | 1 + ...sionsExtensions.kt => KSTypeExtensions.kt} | 5 + .../extensions/KSTypeReferenceExtensions.kt | 28 ++ .../extensions/KSValueParameterExtensions.kt | 15 + .../dsl/processor/ContextAccessorTest.kt | 180 -------- .../dsl/processor/ParameterInjectorTest.kt | 136 ------ .../dsl/processor/TypeParameterHandlerTest.kt | 71 --- .../alchemist/model/deployments/Point.java | 2 +- .../model/positionfilters/Circle.java | 2 - .../model/positionfilters/Rectangle.java | 2 - .../unibo/alchemist/boundary/dsl/DSLLoader.kt | 5 +- .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 10 +- .../boundary/dsl/model/DeploymentContext.kt | 6 +- .../dsl/model/DeploymentsContextImpl.kt | 2 + .../boundary/dsl/model/SimulationContext.kt | 5 +- .../dsl/model/SimulationContextImpl.kt | 7 +- .../boundary/extractors/MoleculeReader.kt | 2 +- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 12 +- .../alchemist/test/GlobalTestReaction.kt | 3 +- 38 files changed, 195 insertions(+), 800 deletions(-) create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectableConstructor.kt rename alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/{KSTypeExtensionsExtensions.kt => KSTypeExtensions.kt} (75%) create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSValueParameterExtensions.kt delete mode 100644 alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt delete mode 100644 alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt delete mode 100644 alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt index 2687907214..67c49d440b 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt @@ -7,7 +7,7 @@ import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType /** Creates expressions for constructor arguments combining injections and call-site values. */ -object ConstructorParamBuilder { +internal object ConstructorParamBuilder { /** * Walks constructor parameters in order and either injects context values * or maps supplied arguments. diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt index 5b26f7b7cb..e2a6289bc8 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt @@ -5,7 +5,7 @@ import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType /** * Provides accessor paths for injected parameters based on context type. */ -object ContextAccessor { +internal object ContextAccessor { /** * Gets the accessor path for an injected parameter based on the context type. * diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt index 8c9e1bde88..32315a1a5b 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt @@ -12,7 +12,7 @@ package it.unibo.alchemist.boundary.dsl.processor /** * Type of context available for parameter injection. */ -enum class ContextType { +internal enum class ContextType { /** Simulation context (only incarnation or only environment). */ SIMULATION_CONTEXT, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt index 0ddc831b3f..06c0c9984d 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt @@ -9,7 +9,7 @@ import java.io.IOException /** * Analyzes and extracts default values from constructor parameters. */ -object DefaultValueAnalyzer { +internal object DefaultValueAnalyzer { private val MATH_CONSTANTS = setOf("PI", "E") private val MATH_FUNCTIONS = setOf( "sin", "cos", "tan", "asin", "acos", "atan", "atan2", diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 32c60b4d8c..dd5888c551 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -17,9 +17,14 @@ import findConstructor import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.boundary.dsl.processor.data.ConstructorInfo import it.unibo.alchemist.boundary.dsl.processor.data.GenerationContext +import it.unibo.alchemist.boundary.dsl.processor.data.InjectableConstructor import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType import it.unibo.alchemist.boundary.dsl.processor.data.TypeParameterInfo +import it.unibo.alchemist.boundary.dsl.processor.extensions.asString +import it.unibo.alchemist.boundary.dsl.processor.extensions.isInjectable +import it.unibo.alchemist.boundary.dsl.processor.extensions.nameOrTypeName +import it.unibo.alchemist.boundary.dsl.processor.extensions.typeName import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation @@ -61,79 +66,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val } } - // Gather all derived state (injections, type params, constructor metadata) before emitting code. - context(resolver: Resolver) - fun buildGenerationContext( - classDecl: KSClassDeclaration, - functionName: String, - parameters: List, - ): GenerationContext { - val injectionIndices = ParameterInjector.findInjectionIndices(parameters) - logger.dslInfo("Injection indices: $injectionIndices") - val contextType = ParameterInjector.determineContextType(injectionIndices) - logger.dslInfo("Determined context type: $contextType") - val paramsToSkip = ParameterInjector.getInjectionParams(injectionIndices, contextType) - val remainingParams = parameters.filterIndexed { index, _ -> !paramsToSkip.contains(index) } - val (initialTypeParamNames, initialTypeParamBounds) = TypeExtractor.extractTypeParameters(classDecl) - val typeParamNames = initialTypeParamNames.toMutableList() - val typeParamBounds = initialTypeParamBounds.toMutableList() - val paramTypes = TypeExtractor.extractParamTypes(remainingParams, typeParamNames) - val paramNames = TypeExtractor.extractParamNames(remainingParams) - val defaultValues = DefaultValueAnalyzer.extractAllDefaultValues(remainingParams, classDecl) - val needsMapEnvironment = checkNeedsMapEnvironment(injectionIndices, parameters) - // Track which parameters are injected so we can include them in the signature/context. - val (injectedParams, injectedParamNames, injectedParamTypesMap) = - processInjectedParams( - injectionIndices, - parameters, - typeParamNames, - typeParamBounds, - ) - val hasInjectedParams = injectedParams.isNotEmpty() - updateTypeParamsForInjected( - hasInjectedParams, - injectionIndices, - parameters, - typeParamNames, - typeParamBounds, - initialTypeParamNames, - initialTypeParamBounds, - ) - addPositionImportIfNeeded(hasInjectedParams, typeParamNames, typeParamBounds, initialTypeParamBounds) - val typeParams = TypeParameterInfo( - names = typeParamNames.toList(), - bounds = typeParamBounds.toList(), - classTypeParamNames = initialTypeParamNames, - classTypeParamBounds = initialTypeParamBounds, - ) - val constructorInfo = ConstructorInfo( - allParameters = parameters, - remainingParams = remainingParams, - paramsToSkip = paramsToSkip, - paramNames = paramNames, - paramTypes = paramTypes, - ) - val injectionContext = InjectionContext( - indices = injectionIndices, - paramNames = injectedParamNames, - paramTypes = injectedParamTypesMap, - contextType = contextType, - hasContextParams = hasInjectedParams, - contextParamName = "ctx", - ) - return GenerationContext( - classDecl = classDecl, - className = classDecl.simpleName.asString(), - functionName = functionName, - typeParams = typeParams, - constructorInfo = constructorInfo, - injectionContext = injectionContext, - injectedParams = injectedParams, - defaultValues = defaultValues, - needsMapEnvironment = needsMapEnvironment, - ) - } - context(resolver: Resolver) private fun processClass(classDeclaration: KSClassDeclaration) { logger.dslInfo("Processing class ${classDeclaration.simpleName.asString()}") @@ -150,311 +82,75 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val writer.println("// This file is generated by Alchemist DSL Processor. Do not edit manually.") writer.println() writer.println("package ${classDeclaration.packageName.asString()}") - val contextualizableConstructors = classDeclaration.getConstructors() - .filter { it.isPublic() } - .map { it to it.parameterTypes } - .filter { (_, parameterTypes) -> - // Only consider constructors with injectable parameters - parameterTypes.any { it in injectableTypes } - } - .distinctBy { (_, parameterTypes) -> parameterTypes - injectableTypes } - .map { it.first } - .toSet() + writer.println() val functionName = classDeclaration.simpleName.asString().replaceFirstChar { it.lowercaseChar() } - contextualizableConstructors.forEach { constructor -> - val typeParameters = constructor.typeParameters - .takeIf { it.isNotEmpty() } - ?.joinToString(prefix = "<", postfix = ">") { + classDeclaration.getConstructors() + .filter { it.isPublic() } + .mapNotNull { InjectableConstructor(it) } + .forEach { (constructor, injectableParams, preservedParams) -> + val context = injectableParams.joinToString(prefix = "context(", postfix = ")") { param -> + "${param.nameOrTypeName()}: ${param.type.asString()}" + } + writer.println(context) + val typeParameters = constructor.typeParameters.takeIf { it.isNotEmpty() } + ?.joinToString(prefix = "<", postfix = "> ") { + buildString { + if (it.isReified) { + append("reified ") + } + append(it.name.asString()) + } + } + .orEmpty() + val parameters = preservedParams.joinToString(separator = NEWLINE_INDENT) { parameter -> buildString { - if (it.isReified) { - append("reified ") + if (parameter.isCrossInline) { + append("crossinline ") + } + if (parameter.isNoInline) { + append("noinline ") } - append(it.name.asString()) + if (parameter.isVararg) { + append("vararg ") + } + append( + "${parameter.name?.asString()}: ${parameter.type.asString()}", + ) } } - .orEmpty() - writer.println( - """ - inline fun $typeParameters $functionName() = TODO() - """.trimIndent(), - ) - } - val constructor = classDeclaration.findConstructor() - if (constructor == null) { - logger.warn("Class ${classDeclaration.simpleName.asString()} has no usable constructor") - return - } - val parameters = constructor.parameters - logger.dslInfo("Found constructor with ${parameters.size} parameters") - parameters.forEachIndexed { index, param -> - val typeName = param.type.resolve().declaration.qualifiedName?.asString() ?: "unknown" - logger.dslInfo("Parameter $index: ${param.name?.asString()} : $typeName") - } -// val generationContext = buildGenerationContext(classDeclaration, functionName, parameters) -// writeGeneratedFile(classDeclaration, generationContext) - } - - fun writeGeneratedFile(classDecl: KSClassDeclaration, context: GenerationContext) { - val containingFile = classDecl.containingFile - val dependencies = if (containingFile != null) { - Dependencies(true, containingFile) - } else { - Dependencies.ALL_FILES - } - val fileName = context.functionName.replaceFirstChar { it.uppercaseChar() } + "Helper" - val file = codeGenerator.createNewFile( - dependencies = dependencies, - packageName = ProcessorConfig.GENERATED_PACKAGE, - fileName = fileName, - ) - PrintWriter(file, true, StandardCharsets.UTF_8).use { writer -> - writeGeneratedCode(writer, context) - } - } - - private fun writeGeneratedCode(writer: PrintWriter, context: GenerationContext) { - writeFileHeader(writer, context.classDecl, context.injectionContext.contextType) - val constructorParams = writeImportsAndFunction(writer, context) - val hasNode = context.injectionContext.indices.containsKey(InjectionType.NODE) - val hasReaction = context.injectionContext.indices.containsKey(InjectionType.REACTION) - if (hasNode && !hasReaction) { - writePropertyContextFunction(writer, context, constructorParams) - } - } - - private fun writeFileHeader(writer: PrintWriter, classDecl: KSClassDeclaration, contextType: ContextType) { - writer.println("@file:Suppress(\"UNCHECKED_CAST\", \"DEPRECATION\")") - writer.println("package ${ProcessorConfig.GENERATED_PACKAGE}") - writer.println() - writer.println("import ${classDecl.qualifiedName?.asString()}") - when (contextType) { - ContextType.SIMULATION_CONTEXT -> writer.println( - "import ${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}", - ) - ContextType.EXPORTER_CONTEXT -> writer.println("import ${ProcessorConfig.ContextTypes.EXPORTER_CONTEXT}") - ContextType.GLOBAL_PROGRAMS_CONTEXT -> writer.println( - "import ${ProcessorConfig.ContextTypes.GLOBAL_PROGRAMS_CONTEXT}", - ) - ContextType.OUTPUT_MONITORS_CONTEXT -> writer.println( - "import ${ProcessorConfig.ContextTypes.OUTPUT_MONITORS_CONTEXT}", - ) - ContextType.TERMINATORS_CONTEXT -> writer.println( - "import ${ProcessorConfig.ContextTypes.TERMINATORS_CONTEXT}", - ) - ContextType.DEPLOYMENTS_CONTEXT -> writer.println( - "import ${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}", - ) - ContextType.DEPLOYMENT_CONTEXT -> writer.println( - "import ${ProcessorConfig.ContextTypes.DEPLOYMENT_CONTEXT}", - ) - ContextType.PROGRAM_CONTEXT -> { - writer.println("import ${ProcessorConfig.ContextTypes.PROGRAM_CONTEXT}") - writer.println("import ${ProcessorConfig.ContextTypes.PROPERTIES_CONTEXT}") - } - ContextType.PROPERTY_CONTEXT -> { - writer.println("import ${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}") - } - } - } - - private fun checkNeedsMapEnvironment( - injectionIndices: Map, - allParameters: List, - ): Boolean { - val envParam = getEnvironmentParameter(injectionIndices, allParameters) ?: return false - val qualifiedName = getQualifiedName(envParam) - return qualifiedName.contains("MapEnvironment") - } - - private fun getEnvironmentParameter( - injectionIndices: Map, - allParameters: List, - ): KSValueParameter? { - val injectionIndicesForEnv = injectionIndices[InjectionType.ENVIRONMENT] ?: return null - return allParameters.getOrNull(injectionIndicesForEnv) - } - - private fun getQualifiedName(param: KSValueParameter): String { - val resolved = param.type.resolve() - return resolved.declaration.qualifiedName?.asString().orEmpty() - } - - private fun processInjectedParams( - injectionIndices: Map, - allParameters: List, - typeParamNames: MutableList, - typeParamBounds: MutableList, - ): Triple>, Map, Map> { - val injectedParams = mutableListOf>() - val injectedParamNames = mutableMapOf() - val injectedParamTypesMap = mutableMapOf() - injectionIndices.forEach { (injectionType, index) -> - val param = allParameters[index] - val paramType = FunctionGenerator.buildContextParamType(param.type, typeParamNames, typeParamBounds) - val paramName = getInjectionParamName(injectionType) - injectedParams.add(paramName to paramType) - injectedParamNames[injectionType] = paramName - injectedParamTypesMap[injectionType] = paramType - } - return Triple(injectedParams, injectedParamNames, injectedParamTypesMap) - } - - private fun getInjectionParamName(injectionType: InjectionType): String = when (injectionType) { - InjectionType.ENVIRONMENT -> "env" - InjectionType.GENERATOR -> "generator" - InjectionType.INCARNATION -> "incarnation" - InjectionType.NODE -> "node" - InjectionType.REACTION -> "reaction" - InjectionType.TIMEDISTRIBUTION -> "td" - InjectionType.FILTER -> "filter" - } - - private fun updateTypeParamsForInjected( - hasInjectedParams: Boolean, - injectionIndices: Map, - allParameters: List, - typeParamNames: MutableList, - typeParamBounds: MutableList, - initialTypeParamNames: List, - initialTypeParamBounds: List, - ) { - if (!hasInjectedParams) { - return - } - val newTypeParams = mutableMapOf() - injectionIndices.forEach { (_, index) -> - val param = allParameters[index] - val initialSize = typeParamNames.size - FunctionGenerator.buildContextParamType(param.type, typeParamNames, typeParamBounds) - - for (i in initialSize until typeParamNames.size) { - val newParam = typeParamNames[i] - val newBound = typeParamBounds[i] - if (!newTypeParams.containsKey(newParam)) { - newTypeParams[newParam] = newBound - } - } - } - val originalTypeParams = initialTypeParamNames.toSet() - val allNewParams = typeParamNames.filter { it !in originalTypeParams } - typeParamNames.clear() - typeParamBounds.clear() - typeParamNames.addAll(initialTypeParamNames) - typeParamBounds.addAll(initialTypeParamBounds) - allNewParams.forEach { param -> - if (!typeParamNames.contains(param)) { - typeParamNames.add(param) - typeParamBounds.add(newTypeParams[param] ?: param) - } - } - } - - private fun addPositionImportIfNeeded( - hasInjectedParams: Boolean, - typeParamNames: MutableList, - typeParamBounds: MutableList, - classTypeParamBounds: List, - ) { - val needsPositionImport = hasInjectedParams && !typeParamBounds.any { it.contains("Position") } - if (needsPositionImport && !typeParamNames.contains("P")) { - val classPIndex = classTypeParamBounds.indexOfFirst { it.contains("Position") } - val pBound = if (classPIndex >= 0) { - val classBound = classTypeParamBounds[classPIndex] - if (classBound.contains(":")) { - val boundPart = classBound.substringAfter(":") - "P:$boundPart" - } else { - "P: ${ProcessorConfig.POSITION_TYPE}

" - } - } else { - "P: it.unibo.alchemist.model.Position

" - } - val tIndex = typeParamNames.indexOf("T") - if (tIndex >= 0) { - typeParamNames.add(tIndex + 1, "P") - typeParamBounds.add(tIndex + 1, pBound) - } else { - if (!typeParamNames.contains("T")) { - typeParamNames.add("T") - typeParamBounds.add("T") + val whereClause = constructor.typeParameters + .flatMap { typeParam -> + typeParam.bounds.map { bound -> + "${typeParam.simpleName.asString()} : ${bound.asString()}" + } + } + .takeIf { it.isNotEmpty() } + ?.joinToString(separator = NEWLINE_INDENT, prefix = "where\n ", postfix = "\n") + .orEmpty() + val arguments = constructor.parameters.joinToString(NEWLINE_INDENT) { + buildString { + if (it.isVararg) { + append("*") + } + append(it.nameOrTypeName()) + } } - typeParamNames.add("P") - typeParamBounds.add(pBound) + writer.println( + """ + |fun $typeParameters$functionName( + | $parameters + |) $whereClause= ${classDeclaration.typeName}( + | $arguments + |) + """.trimMargin(), + ) } - } } - private fun writeImportsAndFunction(writer: PrintWriter, context: GenerationContext): List { - ImportManager.writeImports( - writer, - context.typeParams.bounds, - context.classDecl, - ) - val constructorParams = FunctionGenerator.buildConstructorParams( - context.constructorInfo, - context.injectionContext, - context.typeParams.names, - ) - val functionSignature = FunctionGenerator.buildFunctionSignature( - context.functionName, - context.className, - context.typeParams, - context.constructorInfo, - context.injectedParams, - context.injectionContext.contextType, - ) - writer.println(functionSignature) - val constructorCall = FunctionGenerator.buildConstructorCall( - context.className, - context.typeParams.names, - constructorParams, - context.typeParams.classTypeParamNames, - ) - writer.println(" $constructorCall") - return constructorParams - } + internal companion object { - private fun writePropertyContextFunction( - writer: PrintWriter, - context: GenerationContext, - @Suppress("UNUSED_PARAMETER") constructorParams: List, - ) { - writer.println() - val (tParam, pParam) = TypeParameterHandler.findTAndPParams( - context.typeParams.names, - context.typeParams.bounds, - ) - val pVariance = FunctionGenerator.extractVarianceFromBound(pParam, context.typeParams.bounds) - val pWithVariance = if (pVariance.isNotEmpty()) "$pVariance $pParam" else pParam - val functionTypeParamString = TypeParameterHandler.buildTypeParamString(context.typeParams.bounds) - val returnType = TypeParameterHandler.buildReturnType( - context.className, - context.typeParams.classTypeParamNames, - ) - val contextPart = "context(ctx: ${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}<$tParam, $pWithVariance>) " - val functionParams = FunctionGenerator.buildFunctionParams( - context.constructorInfo.remainingParams, - context.constructorInfo.paramNames, - context.constructorInfo.paramTypes, - ) - val functionSignature = "${contextPart}fun$functionTypeParamString " + - "${context.functionName}$functionParams: $returnType =" - writer.println(functionSignature) - val propertyContextConstructorParams = ConstructorParamBuilder.convertToPropertyContextAccessors( - context.constructorInfo, - context.injectionContext, - context.typeParams.names, - ) - val constructorCall = FunctionGenerator.buildConstructorCall( - context.className, - context.typeParams.names, - propertyContextConstructorParams, - context.typeParams.classTypeParamNames, - ) - writer.println(" $constructorCall") - } + const val NEWLINE_INDENT = ",\n| " - private companion object { private fun KSPLogger.dslInfo(message: String) = info("${DslBuilderProcessor::class.simpleName}: $message") context(resolver: Resolver) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt index 9ce0ea11d8..17a545e5be 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt @@ -7,7 +7,7 @@ import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext import it.unibo.alchemist.boundary.dsl.processor.data.TypeParameterInfo /** Emits the signature, call site, and accessor for generated DSL helpers. */ -object FunctionGenerator { +internal object FunctionGenerator { /** Builds the helper function signature including context and receiver parts. */ fun buildFunctionSignature( functionName: String, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt index d9fbdcbc49..439ee35747 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt @@ -6,7 +6,7 @@ import java.io.PrintWriter /** * Manages writing import statements for generated DSL code. */ -object ImportManager { +internal object ImportManager { /** * Writes all necessary import statements to the generated code file. * diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt index 87b8e7a4cc..c058cb1444 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt @@ -19,7 +19,7 @@ import org.apache.commons.math3.random.RandomGenerator * @property index The parameter index * @property inject Whether to inject this parameter */ -data class InjectionInfo( +internal data class InjectionInfo( /** The type of injection. */ val type: InjectionType, /** The parameter index. */ @@ -31,7 +31,7 @@ data class InjectionInfo( /** * Finds and manages parameter injection indices for context-aware DSL generation. */ -object ParameterInjector { +internal object ParameterInjector { /** * Finds indices of parameters that can be injected from context. * diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt index 5b27b96ff3..1ea0b6b012 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt @@ -11,7 +11,7 @@ import com.google.devtools.ksp.symbol.Variance /** * Processes type arguments for context parameters in DSL builder functions. */ -object TypeArgumentProcessor { +internal object TypeArgumentProcessor { /** * Builds the type string for a context parameter, handling type arguments and bounds. * diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt index 545b41c1f6..8a504768d2 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt @@ -15,7 +15,7 @@ import it.unibo.alchemist.boundary.dsl.processor.extensions.toStringWithGenerics /** * Processes type bounds for type parameters, cleaning up internal Kotlin type representations. */ -object TypeBoundProcessor { +internal object TypeBoundProcessor { /** * Processes a type bound reference, cleaning up internal Kotlin type representations and variance annotations. * diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt index fa4c5cb891..6cd20afa27 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt @@ -9,7 +9,7 @@ import it.unibo.alchemist.boundary.dsl.processor.extensions.toStringWithGenerics /** * Extracts type information from KSP symbols for code generation. */ -object TypeExtractor { +internal object TypeExtractor { /** * Extracts type parameter names and bounds from a class declaration. * diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt index 4640db0806..bd07bba118 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt @@ -8,7 +8,7 @@ import com.google.devtools.ksp.symbol.KSTypeReference * Checks type hierarchies using KSP's type resolution instead of string matching. * This provides more accurate type detection by checking actual type relationships. */ -object TypeHierarchyChecker { +internal object TypeHierarchyChecker { /** * Checks if a type implements or extends a target type by qualified name. * diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt index 6328f9f463..829c43b722 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt @@ -8,7 +8,7 @@ import com.google.devtools.ksp.symbol.Variance /** * Handles type parameter preparation and manipulation for DSL builder functions. */ -object TypeParameterHandler { +internal object TypeParameterHandler { /** * Prepares type parameters by adding T and P parameters if needed for injected parameters. * diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt index 3e9a2e0c17..7eab602ac3 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt @@ -20,7 +20,7 @@ import com.google.devtools.ksp.symbol.KSValueParameter * @property paramNames Names assigned to the remaining parameters. * @property paramTypes Types of the remaining parameters. */ -data class ConstructorInfo( +internal data class ConstructorInfo( val allParameters: List, val remainingParams: List, val paramsToSkip: Set, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt index af31c8d5a7..fad58a731e 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt @@ -24,7 +24,7 @@ import com.google.devtools.ksp.symbol.KSClassDeclaration * @property defaultValues Default values inferred for remaining params. * @property needsMapEnvironment Whether a `MapEnvironment` import is required. */ -data class GenerationContext( +internal data class GenerationContext( val classDecl: KSClassDeclaration, val className: String, val functionName: String, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectableConstructor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectableConstructor.kt new file mode 100644 index 0000000000..935bcc95bf --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectableConstructor.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.data + +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import com.google.devtools.ksp.symbol.KSValueParameter +import it.unibo.alchemist.boundary.dsl.processor.extensions.isInjectable + +internal data class InjectableConstructor( + val constructor: KSFunctionDeclaration, + val injectableParameters: List, + val preservedParameters: List, +) { + companion object { + context(resolver: Resolver) + operator fun invoke(constructor: KSFunctionDeclaration): InjectableConstructor? { + val (injectable, preserved) = constructor.parameters.partition { it.type.resolve().isInjectable() } + return when { + injectable.isNotEmpty() && injectable.toSet().size == injectable.size && injectable.none { + it.isVararg + } -> + InjectableConstructor(constructor, injectable, preserved) + else -> null + } + } + } +} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt index 15567c4510..d475376669 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt @@ -21,7 +21,7 @@ import it.unibo.alchemist.boundary.dsl.processor.ContextType * @property hasContextParams Whether the helper defines context receivers. * @property contextParamName Name of the context parameter used by accessors. */ -data class InjectionContext( +internal data class InjectionContext( val indices: Map, val paramNames: Map, val paramTypes: Map, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt index 8edd511efa..9ed161ec7d 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt @@ -12,7 +12,7 @@ package it.unibo.alchemist.boundary.dsl.processor.data /** * Types of parameters that can be injected from context. */ -enum class InjectionType { +internal enum class InjectionType { /** Environment parameter injection. */ ENVIRONMENT, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt index cde86966c8..ea1224d3a0 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt @@ -17,7 +17,7 @@ package it.unibo.alchemist.boundary.dsl.processor.data * @property classTypeParamNames Original class-level type parameter names. * @property classTypeParamBounds Original class-level type parameter bounds. */ -data class TypeParameterInfo( +internal data class TypeParameterInfo( val names: List, val bounds: List, val classTypeParamNames: List = names, diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt index 8e3d6c8b70..e2e5c01b73 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt @@ -8,6 +8,7 @@ */ import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.google.devtools.ksp.symbol.KSType +import com.google.devtools.ksp.symbol.KSValueParameter /** * Finds a public constructor for the given class declaration. diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensionsExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt similarity index 75% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensionsExtensions.kt rename to alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt index ef6dea04ff..80763b22ed 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensionsExtensions.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt @@ -9,10 +9,15 @@ package it.unibo.alchemist.boundary.dsl.processor.extensions +import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.symbol.KSType +import it.unibo.alchemist.boundary.dsl.processor.DslBuilderProcessor internal fun KSType.toStringWithGenerics(typeParamNames: List): String = "${declaration.typeName}${ arguments.takeIf { it.isNotEmpty() } ?.joinToString(prefix = "<", separator = ", ", postfix = ">") { it.format(typeParamNames) } .orEmpty() }${"?".takeIf { isMarkedNullable }.orEmpty()}" + +context(resolver: Resolver) +internal fun KSType.isInjectable() = DslBuilderProcessor.injectableTypes().any { it.isAssignableFrom(this) } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt new file mode 100644 index 0000000000..6fb40f2eb9 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.extensions + +import com.google.devtools.ksp.symbol.KSTypeParameter +import com.google.devtools.ksp.symbol.KSTypeReference + +internal fun KSTypeReference.asString(): String = buildString { + val type = resolve() + when (val declaration = type.declaration) { + is KSTypeParameter -> append(declaration.simpleName.asString()) + else -> append(declaration.typeName) + } + if (type.arguments.isNotEmpty()) { + append( + type.arguments.joinToString(prefix = "<", postfix = ">") { + it.type?.asString() ?: "*" + }, + ) + } +} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSValueParameterExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSValueParameterExtensions.kt new file mode 100644 index 0000000000..d0921c5e3d --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSValueParameterExtensions.kt @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.extensions + +import com.google.devtools.ksp.symbol.KSValueParameter + +internal fun KSValueParameter.nameOrTypeName(): String = name?.asString() + ?: type.resolve().declaration.simpleName.asString().replaceFirstChar { it.lowercase() } diff --git a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt deleted file mode 100644 index 17b82583df..0000000000 --- a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessorTest.kt +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor - -import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -class ContextAccessorTest { - @Test - fun `test simulation context accessors`() { - assertEquals( - "ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.SIMULATION_CONTEXT), - ) - assertEquals( - "ctx.scenarioGenerator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.SIMULATION_CONTEXT), - ) - assertEquals( - "ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.SIMULATION_CONTEXT), - ) - } - - @Test - fun `test exporter context accessors`() { - assertEquals( - "ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.EXPORTER_CONTEXT), - ) - assertEquals( - "ctx.ctx.scenarioGenerator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.EXPORTER_CONTEXT), - ) - assertEquals( - "ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.EXPORTER_CONTEXT), - ) - } - - @Test - fun `test global programs context accessors`() { - assertEquals( - "ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.GLOBAL_PROGRAMS_CONTEXT), - ) - assertEquals( - "ctx.ctx.scenarioGenerator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.GLOBAL_PROGRAMS_CONTEXT), - ) - assertEquals( - "ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.GLOBAL_PROGRAMS_CONTEXT), - ) - } - - @Test - fun `test output monitors context accessors`() { - assertEquals( - "ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.OUTPUT_MONITORS_CONTEXT), - ) - assertEquals( - "ctx.ctx.scenarioGenerator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.OUTPUT_MONITORS_CONTEXT), - ) - assertEquals( - "ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.OUTPUT_MONITORS_CONTEXT), - ) - } - - @Test - fun `test terminators context accessors`() { - assertEquals( - "ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.TERMINATORS_CONTEXT), - ) - assertEquals( - "ctx.ctx.scenarioGenerator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.TERMINATORS_CONTEXT), - ) - assertEquals( - "ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.TERMINATORS_CONTEXT), - ) - } - - @Test - fun `test deployment context accessors`() { - assertEquals( - "ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENTS_CONTEXT), - ) - assertEquals( - "ctx.generator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.DEPLOYMENTS_CONTEXT), - ) - assertEquals( - "ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.DEPLOYMENTS_CONTEXT), - ) - } - - @Test - fun `test deployment context singular accessors`() { - assertEquals( - "ctx.ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENT_CONTEXT), - ) - assertEquals( - "ctx.ctx.generator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.DEPLOYMENT_CONTEXT), - ) - assertEquals( - "ctx.ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.DEPLOYMENT_CONTEXT), - ) - assertEquals("ctx.filter", ContextAccessor.getAccessor(InjectionType.FILTER, ContextType.DEPLOYMENT_CONTEXT)) - } - - @Test - fun `test program context accessors`() { - assertEquals( - "ctx.ctx.ctx.ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROGRAM_CONTEXT), - ) - assertEquals( - "ctx.ctx.ctx.ctx.generator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROGRAM_CONTEXT), - ) - assertEquals( - "ctx.ctx.ctx.ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.PROGRAM_CONTEXT), - ) - assertEquals("ctx.node", ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROGRAM_CONTEXT)) - assertEquals("ctx.reaction", ContextAccessor.getAccessor(InjectionType.REACTION, ContextType.PROGRAM_CONTEXT)) - assertEquals( - "ctx.timeDistribution!!", - ContextAccessor.getAccessor(InjectionType.TIMEDISTRIBUTION, ContextType.PROGRAM_CONTEXT), - ) - } - - @Test - fun `test property context accessors`() { - assertEquals( - "ctx.ctx.ctx.ctx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.PROPERTY_CONTEXT), - ) - assertEquals( - "ctx.ctx.ctx.ctx.generator", - ContextAccessor.getAccessor(InjectionType.GENERATOR, ContextType.PROPERTY_CONTEXT), - ) - assertEquals( - "ctx.ctx.ctx.ctx.ctx.incarnation", - ContextAccessor.getAccessor(InjectionType.INCARNATION, ContextType.PROPERTY_CONTEXT), - ) - assertEquals("ctx.node", ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROPERTY_CONTEXT)) - } - - @Test - fun `test custom context parameter name`() { - assertEquals( - "customCtx.ctx.environment", - ContextAccessor.getAccessor(InjectionType.ENVIRONMENT, ContextType.DEPLOYMENTS_CONTEXT, "customCtx"), - ) - assertEquals( - "customCtx.node", - ContextAccessor.getAccessor(InjectionType.NODE, ContextType.PROGRAM_CONTEXT, "customCtx"), - ) - } -} diff --git a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt deleted file mode 100644 index 80063a5e9b..0000000000 --- a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjectorTest.kt +++ /dev/null @@ -1,136 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType -import kotlin.test.assertEquals -import org.junit.jupiter.api.Test - -class ParameterInjectorTest { - @Test - fun `test determineContextType with node and reaction`() { - val injectionIndices = mapOf( - InjectionType.NODE to 0, - InjectionType.REACTION to 1, - ) - val contextType = ParameterInjector.determineContextType(injectionIndices) - assertEquals(ContextType.PROGRAM_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with only environment`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val contextType = ParameterInjector.determineContextType(injectionIndices) - assertEquals(ContextType.SIMULATION_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with only incarnation`() { - val injectionIndices = mapOf( - InjectionType.INCARNATION to 0, - ) - val contextType = ParameterInjector.determineContextType(injectionIndices) - assertEquals(ContextType.SIMULATION_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with environment and generator`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - InjectionType.GENERATOR to 1, - ) - val contextType = ParameterInjector.determineContextType(injectionIndices) - assertEquals(ContextType.DEPLOYMENTS_CONTEXT, contextType) - } - - @Test - fun `test getInjectionParams with all enabled`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - InjectionType.GENERATOR to 1, - InjectionType.NODE to 2, - ) - val paramsToSkip = ParameterInjector.getInjectionParams( - injectionIndices, - ContextType.PROGRAM_CONTEXT, - ) - assertEquals(setOf(0, 1, 2), paramsToSkip) - } - - @Test - fun `test getInjectionParams with time distribution always injected`() { - val injectionIndices = mapOf( - InjectionType.TIMEDISTRIBUTION to 0, - ) - val paramsToSkip = ParameterInjector.getInjectionParams( - injectionIndices, - ContextType.PROGRAM_CONTEXT, - ) - assertEquals(setOf(0), paramsToSkip) - } - - @Test - fun `test getInjectionParams with GlobalProgramsContext only injects available parameters`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - InjectionType.TIMEDISTRIBUTION to 1, - ) - val paramsToSkip = ParameterInjector.getInjectionParams( - injectionIndices, - ContextType.GLOBAL_PROGRAMS_CONTEXT, - ) - - assertEquals(setOf(0), paramsToSkip) - } - - @Test - fun `test determineContextType with filter parameter`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - InjectionType.FILTER to 1, - ) - val contextType = ParameterInjector.determineContextType(injectionIndices) - assertEquals(ContextType.DEPLOYMENT_CONTEXT, contextType) - } - - @Test - fun `test determineContextType with invalid scope falls back to automatic detection`() { - val injectionIndices = mapOf( - InjectionType.ENVIRONMENT to 0, - ) - val contextType = ParameterInjector.determineContextType(injectionIndices) - assertEquals(ContextType.SIMULATION_CONTEXT, contextType) - } - - @Test - fun `test parseScope with valid values`() { - assertEquals(ContextType.PROGRAM_CONTEXT, ParameterInjector.parseScope("PROGRAM")) - assertEquals(ContextType.SIMULATION_CONTEXT, ParameterInjector.parseScope("SIMULATION")) - assertEquals(ContextType.SIMULATION_CONTEXT, ParameterInjector.parseScope("SIMULATION_CONTEXT")) - assertEquals(ContextType.EXPORTER_CONTEXT, ParameterInjector.parseScope("EXPORTER")) - assertEquals(ContextType.EXPORTER_CONTEXT, ParameterInjector.parseScope("EXPORTER_CONTEXT")) - assertEquals(ContextType.GLOBAL_PROGRAMS_CONTEXT, ParameterInjector.parseScope("GLOBAL_PROGRAMS")) - assertEquals(ContextType.GLOBAL_PROGRAMS_CONTEXT, ParameterInjector.parseScope("GLOBAL_PROGRAMS_CONTEXT")) - assertEquals(ContextType.OUTPUT_MONITORS_CONTEXT, ParameterInjector.parseScope("OUTPUT_MONITORS")) - assertEquals(ContextType.OUTPUT_MONITORS_CONTEXT, ParameterInjector.parseScope("OUTPUT_MONITORS_CONTEXT")) - assertEquals(ContextType.TERMINATORS_CONTEXT, ParameterInjector.parseScope("TERMINATORS")) - assertEquals(ContextType.TERMINATORS_CONTEXT, ParameterInjector.parseScope("TERMINATORS_CONTEXT")) - assertEquals(ContextType.DEPLOYMENTS_CONTEXT, ParameterInjector.parseScope("DEPLOYMENT")) - assertEquals(ContextType.DEPLOYMENTS_CONTEXT, ParameterInjector.parseScope("DEPLOYMENTS_CONTEXT")) - assertEquals(ContextType.DEPLOYMENT_CONTEXT, ParameterInjector.parseScope("DEPLOYMENT_CONTEXT")) - assertEquals(ContextType.PROPERTY_CONTEXT, ParameterInjector.parseScope("PROPERTY")) - assertEquals(ContextType.PROPERTY_CONTEXT, ParameterInjector.parseScope("PROPERTY_CONTEXT")) - assertEquals(ContextType.PROGRAM_CONTEXT, ParameterInjector.parseScope("PROGRAM_CONTEXT")) - assertEquals(ContextType.PROGRAM_CONTEXT, ParameterInjector.parseScope("program")) - assertEquals(ContextType.SIMULATION_CONTEXT, ParameterInjector.parseScope("simulation")) - assertEquals(ContextType.DEPLOYMENTS_CONTEXT, ParameterInjector.parseScope("deployments_context")) - assertEquals(ContextType.EXPORTER_CONTEXT, ParameterInjector.parseScope("exporter")) - } - - @Test - fun `test parseScope with invalid values`() { - assertEquals(null, ParameterInjector.parseScope("INVALID")) - assertEquals(null, ParameterInjector.parseScope("")) - assertEquals(null, ParameterInjector.parseScope(null)) - } -} diff --git a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt b/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt deleted file mode 100644 index 297f66babd..0000000000 --- a/alchemist-dsl-processor/src/jvmTest/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandlerTest.kt +++ /dev/null @@ -1,71 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test - -class TypeParameterHandlerTest { - @Test - fun `test buildTypeParamString with single parameter`() { - val typeParamBounds = listOf("T") - val result = TypeParameterHandler.buildTypeParamString(typeParamBounds) - - assertEquals("", result) - } - - @Test - fun `test buildTypeParamString with multiple parameters`() { - val typeParamBounds = listOf("T", "P: it.unibo.alchemist.model.Position

") - val result = TypeParameterHandler.buildTypeParamString(typeParamBounds) - - assertEquals(">", result) - } - - @Test - fun `test buildTypeParamString with empty list`() { - val typeParamBounds = emptyList() - val result = TypeParameterHandler.buildTypeParamString(typeParamBounds) - - assertEquals("", result) - } - - @Test - fun `test buildReturnType with type parameters`() { - val className = "TestClass" - val typeParamNames = listOf("T", "P") - val result = TypeParameterHandler.buildReturnType(className, typeParamNames) - - assertEquals("TestClass", result) - } - - @Test - fun `test buildReturnType without type parameters`() { - val className = "TestClass" - val typeParamNames = emptyList() - val result = TypeParameterHandler.buildReturnType(className, typeParamNames) - - assertEquals("TestClass", result) - } - - @Test - fun `test findTAndPParams`() { - val typeParamNames = listOf("T", "P") - val typeParamBounds = listOf("T", "P: it.unibo.alchemist.model.Position

") - - val (tParam, pParam) = TypeParameterHandler.findTAndPParams(typeParamNames, typeParamBounds) - - assertEquals("T", tParam) - assertEquals("P", pParam) - } - - @Test - fun `test findTAndPParams with only T`() { - val typeParamNames = listOf("T") - val typeParamBounds = listOf("T") - - val (tParam, pParam) = TypeParameterHandler.findTAndPParams(typeParamNames, typeParamBounds) - - assertEquals("T", tParam) - assertEquals("P", pParam) - } -} diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java index ecaa271c16..16c1cfdcee 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java @@ -22,7 +22,7 @@ * * @param

position type */ -@AlchemistKotlinDSL(scope = "DEPLOYMENTS_CONTEXT") +@AlchemistKotlinDSL public final class Point

> implements Deployment

{ private final double x; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java index 9cb07c8745..785cf8d116 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Circle.java @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.positionfilters; -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Position2D; import java.awt.geom.Ellipse2D; @@ -19,7 +18,6 @@ * * @param

Position type */ -@AlchemistKotlinDSL(functionName = "CircleFilter") public class Circle

> extends Abstract2DShape

{ /** diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java index 41945306e8..96685b2726 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.positionfilters; -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Position2D; import java.awt.geom.Rectangle2D; @@ -22,7 +21,6 @@ * * @param

position type */ -@AlchemistKotlinDSL(functionName = "RectangleFilter") public class Rectangle

> extends Abstract2DShape

{ /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt index 44c62ee850..9964889d3b 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt @@ -11,6 +11,7 @@ package it.unibo.alchemist.boundary.dsl import it.unibo.alchemist.boundary.Exporter import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.dsl.model.SimulationContext import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl import it.unibo.alchemist.boundary.exporters.GlobalExporter import it.unibo.alchemist.core.Engine @@ -25,12 +26,12 @@ import java.util.concurrent.Semaphore * @param ctx The simulation context. */ abstract class DSLLoader>( - private val ctx: SimulationContextImpl<*, *>, + private val ctx: SimulationContext<*, *>, private val envFactory: () -> Environment<*, *>, ) : Loader { override fun > getWith(values: Map): Simulation = SingleUseLoader(ctx).load(values) - private inner class SingleUseLoader(private val ctx: SimulationContextImpl<*, *>) { + private inner class SingleUseLoader(private val ctx: SimulationContext<*, *>) { private val mutex = Semaphore(1) private var consumed = false diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index 4a01f97d85..f2065a20e2 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -93,15 +93,19 @@ object Dsl { * @param block The simulation configuration block. * @return A loader instance. */ - fun > simulation( + fun simulation( incarnation: Incarnation, - block: SimulationContext.() -> Unit, + block: context(Environment) SimulationContext.() -> Unit, ): Loader { @Suppress("UNCHECKED_CAST") val defaultEnv = { Continuous2DEnvironment(incarnation) } val ctx = SimulationContextImpl(incarnation) @Suppress("UNCHECKED_CAST") - ctx.apply(block) + ctx.apply { + context(ctx.environment) { + block() + } + } return createLoader(ctx, defaultEnv) } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt index 759e67d2b0..1c30beaf77 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt @@ -11,6 +11,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.dsl.AlchemistDsl import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter @@ -90,7 +91,10 @@ interface DeploymentsContext> { * @param deployment The deployment that defines node positions. * @see [Deployment] */ - fun deploy(deployment: Deployment<*>) + context(environment: Environment) + fun deploy( + deployment: Deployment<*>, + ) } /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt index ea25cdff40..ec1690371d 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt @@ -12,6 +12,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter @@ -42,6 +43,7 @@ open class DeploymentsContextImpl>(override val ctx: Simulati populateDeployment(d) } + context(environment: Environment) override fun deploy(deployment: Deployment<*>) { @Suppress("UNCHECKED_CAST") this.deploy(deployment) {} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index e87bd38d30..432f77c064 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -127,7 +127,10 @@ interface SimulationContext> { * * @see [DeploymentsContextImpl] to configure deployments */ - fun deployments(block: DeploymentsContext.() -> Unit) + context(environment: Environment) + fun deployments( + block: DeploymentsContext.() -> Unit, + ) /** * Adds a termination predicate to the simulation. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt index afce09c7d9..f8c5c66a75 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -32,9 +32,11 @@ import org.apache.commons.math3.random.RandomGenerator * @param P The type of position. */ -class SimulationContextImpl>(override val incarnation: Incarnation) : SimulationContext { +class SimulationContextImpl>( + override val incarnation: Incarnation, + private var envIstance: Environment? = null, +) : SimulationContext { /** The environment instance (internal use). */ - var envIstance: Environment? = null override val environment: Environment get() = requireNotNull(envIstance) { "Environment has not been initialized yet" } @@ -110,6 +112,7 @@ class SimulationContextImpl>(override val incarnation: Incarn return batchContext } + context(environment: Environment) override fun deployments(block: DeploymentsContext.() -> Unit) { logger.debug("adding deployments block inside {}", this) buildSteps.add { diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt index 7022e6adfb..a9a5c757aa 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt @@ -35,7 +35,7 @@ import kotlin.math.min * aggregating data. If an empty list is passed, then the values * will be logged indipendently for each node. */ -@AlchemistKotlinDSL(scope = "EXPORTER_CONTEXT") +@AlchemistKotlinDSL class MoleculeReader @JvmOverloads constructor( diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index e11e51d269..e27d1ac1cf 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -7,23 +7,12 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -@file:Suppress("UNCHECKED_CAST", "DEPRECATION") - package it.unibo.alchemist.dsl import another.location.SimpleMonitor import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.dsl.generated.RectangleFilter -import it.unibo.alchemist.boundary.dsl.generated.circle -import it.unibo.alchemist.boundary.dsl.generated.globalTestReaction -import it.unibo.alchemist.boundary.dsl.generated.grid -import it.unibo.alchemist.boundary.dsl.generated.moleculeReader -import it.unibo.alchemist.boundary.dsl.generated.point -import it.unibo.alchemist.boundary.dsl.generated.polygon -import it.unibo.alchemist.boundary.dsl.generated.testNode -import it.unibo.alchemist.boundary.dsl.generated.testNodeProperty import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.PROTELIS import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.SAPERE import it.unibo.alchemist.boundary.exporters.CSVExporter @@ -39,6 +28,7 @@ import it.unibo.alchemist.model.actions.BrownianMove import it.unibo.alchemist.model.deployments.Circle import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.layers.StepLayer import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance diff --git a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt index de7f2d97e2..daca33f6a1 100644 --- a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt +++ b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.test -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Condition @@ -20,7 +19,7 @@ import it.unibo.alchemist.model.Time import it.unibo.alchemist.model.TimeDistribution import org.danilopianini.util.ListSet import org.danilopianini.util.ListSets -@AlchemistKotlinDSL(scope = "GLOBAL_PROGRAMS_CONTEXT") + class GlobalTestReaction(override val timeDistribution: TimeDistribution, val environment: Environment) : GlobalReaction { override fun compareTo(other: Actionable): Int = tau.compareTo(other.tau) From 418a8ead0802ab35ca6b7bfb7b6a15422ac4df01 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Tue, 23 Dec 2025 16:48:41 +0100 Subject: [PATCH 108/196] refactor: suppress Detekt false positives for undocumented public functions in context interfaces --- .../alchemist/boundary/dsl/model/DeploymentContext.kt | 8 ++------ .../alchemist/boundary/dsl/model/SimulationContext.kt | 6 ++---- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt index 1c30beaf77..36efda469e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt @@ -50,7 +50,7 @@ import org.apache.commons.math3.random.RandomGenerator * @see [Deployment] for the deployment interface * @see [DeploymentContext] for configuring individual deployments */ -@AlchemistDsl +@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters interface DeploymentsContext> { /** * The simulation context this deployments context belongs to. @@ -92,9 +92,7 @@ interface DeploymentsContext> { * @see [Deployment] */ context(environment: Environment) - fun deploy( - deployment: Deployment<*>, - ) + fun deploy(deployment: Deployment<*>) } /** @@ -111,7 +109,6 @@ interface DeploymentsContext> { * @see [ProgramsContext] for configuring node programs * @see [PropertiesContext] for configuring node properties */ -@AlchemistDsl interface DeploymentContext> { /** * The deployments context this deployment context belongs to. @@ -219,7 +216,6 @@ interface DeploymentContext> { * @see [it.unibo.alchemist.model.Incarnation.createMolecule] * @see [it.unibo.alchemist.model.Incarnation.createConcentration] */ -@AlchemistDsl interface ContentContext> { /** * The optional position filter applied to this content context. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 432f77c064..cc190aee43 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -55,7 +55,7 @@ import org.apache.commons.math3.random.RandomGenerator * @see [ExporterContextImpl] for exporter configuration * @see [LayerContextImpl] for layer configuration */ -@AlchemistDsl +@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters interface SimulationContext> { /** * The incarnation instance that defines how molecules, nodes, and reactions are created. @@ -128,9 +128,7 @@ interface SimulationContext> { * @see [DeploymentsContextImpl] to configure deployments */ context(environment: Environment) - fun deployments( - block: DeploymentsContext.() -> Unit, - ) + fun deployments(block: DeploymentsContext.() -> Unit) /** * Adds a termination predicate to the simulation. From 5275f1a4c776f4012af53b2f22a6ebf1647718cb Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Tue, 23 Dec 2025 17:05:51 +0100 Subject: [PATCH 109/196] refactor: streamline DslBuilderProcessor by removing unused imports and simplifying constructor processing --- .../dsl/processor/ConstructorParamBuilder.kt | 247 ----------- .../boundary/dsl/processor/ContextAccessor.kt | 148 ------- .../boundary/dsl/processor/ContextType.kt | 42 -- .../dsl/processor/DefaultValueAnalyzer.kt | 396 ------------------ .../dsl/processor/DslBuilderProcessor.kt | 125 +++--- .../dsl/processor/FunctionGenerator.kt | 177 -------- .../boundary/dsl/processor/ImportManager.kt | 22 - .../dsl/processor/ParameterInjector.kt | 222 ---------- .../boundary/dsl/processor/ProcessorConfig.kt | 75 ---- .../dsl/processor/TypeArgumentProcessor.kt | 199 --------- .../dsl/processor/TypeBoundProcessor.kt | 60 --- .../boundary/dsl/processor/TypeExtractor.kt | 92 ---- .../dsl/processor/TypeHierarchyChecker.kt | 119 ------ .../dsl/processor/TypeParameterHandler.kt | 203 --------- .../dsl/processor/data/ConstructorInfo.kt | 29 -- .../dsl/processor/data/GenerationContext.kt | 37 -- .../dsl/processor/data/InjectionContext.kt | 31 -- .../dsl/processor/data/InjectionType.kt | 36 -- .../dsl/processor/data/TypeParameterInfo.kt | 25 -- .../KSClassDeclarationExtensions.kt | 23 - .../extensions/KSTypeArgumentExtensions.kt | 31 -- .../processor/extensions/KSTypeExtensions.kt | 6 - 22 files changed, 61 insertions(+), 2284 deletions(-) delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclarationExtensions.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt deleted file mode 100644 index 67c49d440b..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ConstructorParamBuilder.kt +++ /dev/null @@ -1,247 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSTypeReference -import com.google.devtools.ksp.symbol.KSValueParameter -import it.unibo.alchemist.boundary.dsl.processor.data.ConstructorInfo -import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext -import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType - -/** Creates expressions for constructor arguments combining injections and call-site values. */ -internal object ConstructorParamBuilder { - /** - * Walks constructor parameters in order and either injects context values - * or maps supplied arguments. - */ - fun buildConstructorParams( - constructorInfo: ConstructorInfo, - injectionContext: InjectionContext, - typeParamNames: List, - ): List = buildConstructorParamsInternal( - constructorInfo, - injectionContext, - typeParamNames, - ) - - private fun isInjectionIndex( - injectionType: InjectionType, - index: Int, - injectionIndices: Map, - ): Boolean = injectionIndices.containsKey(injectionType) && index == injectionIndices[injectionType] - - private fun buildInjectedParam( - injectionType: InjectionType, - param: KSValueParameter, - injectionContext: InjectionContext, - typeParamNames: List, - ): String { - val accessor = buildAccessor(injectionType, injectionContext) - val contextParamType = injectionContext.paramTypes[injectionType] - return if (contextParamType != null && needsCast(param.type, contextParamType, typeParamNames)) { - val castType = TypeExtractor.extractTypeString(param.type, typeParamNames) - "$accessor as $castType" - } else { - accessor - } - } - - private fun buildAccessor(injectionType: InjectionType, injectionContext: InjectionContext): String { - if (!injectionContext.hasContextParams) { - return injectionContext.paramNames[injectionType] ?: getDefaultParamName(injectionType) - } - return ContextAccessor.getAccessor( - injectionType, - injectionContext.contextType, - injectionContext.contextParamName, - ) - } - - private fun getDefaultParamName(injectionType: InjectionType): String = injectionType.name.lowercase() - - private fun needsCast( - constructorParamType: KSTypeReference, - contextParamType: String, - typeParamNames: List, - ): Boolean { - val constructorTypeStr = TypeExtractor.extractTypeString(constructorParamType, typeParamNames) - if (constructorTypeStr == contextParamType) { - return false - } - val constructorResolved = constructorParamType.resolve() - val constructorDecl = constructorResolved.declaration - val constructorQualified = constructorDecl.qualifiedName?.asString().orEmpty() - return when { - !contextParamType.startsWith(constructorQualified) -> true - constructorResolved.arguments.isEmpty() -> false - else -> checkWildcardCastNeeded(constructorTypeStr, contextParamType, typeParamNames) - } - } - - private fun checkWildcardCastNeeded( - constructorTypeStr: String, - contextParamType: String, - typeParamNames: List, - ): Boolean { - val constructorHasWildcards = constructorTypeStr.contains("<") && - (constructorTypeStr.contains("<*") || constructorTypeStr.contains(", *")) - if (constructorHasWildcards) { - val contextTypeArgs = if (contextParamType.contains("<")) { - contextParamType.substringAfter("<").substringBefore(">") - } else { - "" - } - return typeParamNames.any { it in contextTypeArgs } - } - return constructorTypeStr != contextParamType - } - - /** Builds constructor params when a property context is applied. */ - fun buildConstructorParamsForPropertyContext( - constructorInfo: ConstructorInfo, - injectionContext: InjectionContext, - typeParamNames: List, - ): List { - val propertyContext = injectionContext.copy( - hasContextParams = true, - contextType = ContextType.PROPERTY_CONTEXT, - contextParamName = "ctx", - ) - return buildConstructorParamsInternal( - constructorInfo, - propertyContext, - typeParamNames, - ) - } - - /** Converts regular constructors into property-context-style accessors. */ - fun convertToPropertyContextAccessors( - constructorInfo: ConstructorInfo, - injectionContext: InjectionContext, - typeParamNames: List, - ): List { - val propertyCONTEXTContext = injectionContext.copy( - hasContextParams = true, - contextType = ContextType.PROPERTY_CONTEXT, - contextParamName = "ctx", - ) - return buildConstructorParamsInternal( - constructorInfo, - propertyCONTEXTContext, - typeParamNames, - ) - } - - private fun buildConstructorParamsInternal( - constructorInfo: ConstructorInfo, - injectionContext: InjectionContext, - typeParamNames: List, - ): List { - val constructorParams = mutableListOf() - var remainingIndex = 0 - constructorInfo.allParameters.forEachIndexed { index, param -> - val paramExpr = buildParamExpression( - index, - param, - remainingIndex, - constructorInfo, - injectionContext, - typeParamNames, - ) - constructorParams.add(paramExpr.first) - if (paramExpr.second) { - remainingIndex++ - } - } - return constructorParams - } - - private fun buildParamExpression( - index: Int, - param: KSValueParameter, - remainingIndex: Int, - constructorInfo: ConstructorInfo, - injectionContext: InjectionContext, - typeParamNames: List, - ): Pair { - val injectionType = findInjectionType(index, injectionContext, constructorInfo.paramsToSkip) - if (injectionType != null) { - return buildInjectedParamExpression(injectionType, param, injectionContext, typeParamNames) - } - return buildRegularParamExpression(index, remainingIndex, constructorInfo) - } - - private fun buildInjectedParamExpression( - injectionType: InjectionType, - param: KSValueParameter, - injectionContext: InjectionContext, - typeParamNames: List, - ): Pair { - val accessor = buildInjectedParam(injectionType, param, injectionContext, typeParamNames) - return Pair(accessor, false) - } - - private fun buildRegularParamExpression( - index: Int, - remainingIndex: Int, - constructorInfo: ConstructorInfo, - ): Pair { - if (!constructorInfo.paramsToSkip.contains(index)) { - val paramName = constructorInfo.paramNames[remainingIndex] - val remainingParam = constructorInfo.remainingParams[remainingIndex] - val paramValue = if (remainingParam.isVararg) "*$paramName" else paramName - return Pair(paramValue, true) - } - return Pair("null", false) - } - - private fun findInjectionType( - index: Int, - injectionContext: InjectionContext, - paramsToSkip: Set, - ): InjectionType? { - val injectionTypes = listOf( - Triple(InjectionType.ENVIRONMENT, "injectEnvironment", true), - Triple(InjectionType.GENERATOR, "injectGenerator", true), - Triple(InjectionType.INCARNATION, "injectIncarnation", true), - Triple(InjectionType.NODE, "injectNode", true), - Triple(InjectionType.REACTION, "injectReaction", true), - Triple(InjectionType.TIMEDISTRIBUTION, "", false), - Triple(InjectionType.FILTER, "", false), - ) - return findInjectionTypeFromList(index, injectionContext, paramsToSkip, injectionTypes) - } - - private fun findInjectionTypeFromList( - index: Int, - injectionContext: InjectionContext, - paramsToSkip: Set, - injectionTypes: List>, - ): InjectionType? { - for ((type, _, checkAnnotation) in injectionTypes) { - val matchesAnnotation = checkAnnotation && - isInjectionIndex( - type, - index, - injectionContext.indices, - ) - val matchesFallback = !checkAnnotation && matchesFallbackInjection( - index, - type, - injectionContext.indices, - paramsToSkip, - ) - if (matchesAnnotation || matchesFallback) { - return type - } - } - return null - } - - private fun matchesFallbackInjection( - index: Int, - type: InjectionType, - injectionIndices: Map, - paramsToSkip: Set, - ): Boolean = paramsToSkip.contains(index) && - injectionIndices.containsKey(type) && - index == injectionIndices[type] -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt deleted file mode 100644 index e2a6289bc8..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextAccessor.kt +++ /dev/null @@ -1,148 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType - -/** - * Provides accessor paths for injected parameters based on context type. - */ -internal object ContextAccessor { - /** - * Gets the accessor path for an injected parameter based on the context type. - * - * @param injectionType The type of injection - * @param contextType The context type - * @param contextParamName The name of the context parameter (default: "ctx") - * @return The accessor path string - */ - fun getAccessor(injectionType: InjectionType, contextType: ContextType, contextParamName: String = "ctx"): String = - when (contextType) { - ContextType.SIMULATION_CONTEXT -> getSimulationAccessor(injectionType, contextParamName) - ContextType.EXPORTER_CONTEXT -> getExporterContextAccessor(injectionType, contextParamName) - ContextType.GLOBAL_PROGRAMS_CONTEXT -> getGlobalProgramsContextAccessor(injectionType, contextParamName) - ContextType.OUTPUT_MONITORS_CONTEXT -> getOutputMonitorsContextAccessor(injectionType, contextParamName) - ContextType.TERMINATORS_CONTEXT -> getTerminatorsContextAccessor(injectionType, contextParamName) - ContextType.DEPLOYMENTS_CONTEXT -> getDeploymentsContextAccessor(injectionType, contextParamName) - ContextType.DEPLOYMENT_CONTEXT -> getDeploymentContextAccessor(injectionType, contextParamName) - ContextType.PROGRAM_CONTEXT -> getProgramAccessor(injectionType, contextParamName) - ContextType.PROPERTY_CONTEXT -> getPropertyAccessor(injectionType, contextParamName) - } - - private fun getSimulationAccessor(injectionType: InjectionType, contextParamName: String): String = - when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.environment" - InjectionType.GENERATOR -> "$contextParamName.scenarioGenerator" - InjectionType.INCARNATION -> "$contextParamName.incarnation" - InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in SimulationContext") - InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in SimulationContext") - InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( - "TIMEDISTRIBUTION is not available in SimulationContext", - ) - InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in SimulationContext") - } - - private fun getExporterContextAccessor(injectionType: InjectionType, contextParamName: String): String = - when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.environment" - InjectionType.GENERATOR -> "$contextParamName.ctx.scenarioGenerator" - InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" - InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in ExporterContext") - InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in ExporterContext") - InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( - "TIMEDISTRIBUTION is not available in ExporterContext", - ) - InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in ExporterContext") - } - - private fun getGlobalProgramsContextAccessor(injectionType: InjectionType, contextParamName: String): String = - when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.environment" - InjectionType.GENERATOR -> "$contextParamName.ctx.scenarioGenerator" - InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" - InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in GlobalProgramsContext") - InjectionType.REACTION -> throw IllegalArgumentException( - "REACTION is not available in GlobalProgramsContext", - ) - InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( - "TIMEDISTRIBUTION is not available in GlobalProgramsContext", - ) - InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in GlobalProgramsContext") - } - - private fun getOutputMonitorsContextAccessor(injectionType: InjectionType, contextParamName: String): String = - when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.environment" - InjectionType.GENERATOR -> "$contextParamName.ctx.scenarioGenerator" - InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" - InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in OutputMonitorsContext") - InjectionType.REACTION -> throw IllegalArgumentException( - "REACTION is not available in OutputMonitorsContext", - ) - InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( - "TIMEDISTRIBUTION is not available in OutputMonitorsContext", - ) - InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in OutputMonitorsContext") - } - - private fun getTerminatorsContextAccessor(injectionType: InjectionType, contextParamName: String): String = - when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.environment" - InjectionType.GENERATOR -> "$contextParamName.ctx.scenarioGenerator" - InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" - InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in TerminatorsContext") - InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in TerminatorsContext") - InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( - "TIMEDISTRIBUTION is not available in TerminatorsContext", - ) - InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in TerminatorsContext") - } - - private fun getDeploymentsContextAccessor(injectionType: InjectionType, contextParamName: String): String = - when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.environment" - InjectionType.GENERATOR -> "$contextParamName.generator" - InjectionType.INCARNATION -> "$contextParamName.ctx.incarnation" - InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in DeploymentsContext") - InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in DeploymentsContext") - InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( - "TIMEDISTRIBUTION is not available in DeploymentsContext", - ) - InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in DeploymentsContext") - } - - private fun getDeploymentContextAccessor(injectionType: InjectionType, contextParamName: String): String = - when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.environment" - InjectionType.GENERATOR -> "$contextParamName.ctx.generator" - InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.incarnation" - InjectionType.FILTER -> "$contextParamName.filter" - InjectionType.NODE -> throw IllegalArgumentException("NODE is not available in DeploymentContext") - InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in DeploymentContext") - InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( - "TIMEDISTRIBUTION is not available in DeploymentContext", - ) - } - - private fun getProgramAccessor(injectionType: InjectionType, contextParamName: String): String = - when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.ctx.ctx.environment" - InjectionType.GENERATOR -> "$contextParamName.ctx.ctx.ctx.generator" - InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.ctx.ctx.incarnation" - InjectionType.NODE -> "$contextParamName.node" - InjectionType.REACTION -> "$contextParamName.reaction" - InjectionType.TIMEDISTRIBUTION -> "$contextParamName.timeDistribution!!" - InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in ProgramContext") - } - - private fun getPropertyAccessor(injectionType: InjectionType, contextParamName: String): String = - when (injectionType) { - InjectionType.ENVIRONMENT -> "$contextParamName.ctx.ctx.ctx.ctx.environment" - InjectionType.GENERATOR -> "$contextParamName.ctx.ctx.ctx.generator" - InjectionType.INCARNATION -> "$contextParamName.ctx.ctx.ctx.ctx.incarnation" - InjectionType.NODE -> "$contextParamName.node" - InjectionType.REACTION -> throw IllegalArgumentException("REACTION is not available in PropertyContext") - InjectionType.TIMEDISTRIBUTION -> throw IllegalArgumentException( - "TIMEDISTRIBUTION is not available in PropertyContext", - ) - InjectionType.FILTER -> throw IllegalArgumentException("FILTER is not available in PropertyContext") - } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt deleted file mode 100644 index 32315a1a5b..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ContextType.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor - -/** - * Type of context available for parameter injection. - */ -internal enum class ContextType { - /** Simulation context (only incarnation or only environment). */ - SIMULATION_CONTEXT, - - /** Exporter context (one level below SimulationContext, manually settable). */ - EXPORTER_CONTEXT, - - /** Global programs context (one level below SimulationContext, manually settable). */ - GLOBAL_PROGRAMS_CONTEXT, - - /** Output monitors context (one level below SimulationContext, manually settable). */ - OUTPUT_MONITORS_CONTEXT, - - /** Terminators context (one level below SimulationContext, manually settable). */ - TERMINATORS_CONTEXT, - - /** Deployments context (generator). */ - DEPLOYMENTS_CONTEXT, - - /** Deployment context (singular, one level below DeploymentsContext, includes filter). */ - DEPLOYMENT_CONTEXT, - - /** Program context (includes node, reaction, and time distribution). */ - PROGRAM_CONTEXT, - - /** Property context (includes node, same depth as program context). */ - PROPERTY_CONTEXT, -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt deleted file mode 100644 index 06c0c9984d..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DefaultValueAnalyzer.kt +++ /dev/null @@ -1,396 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.containingFile -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSValueParameter -import java.io.File -import java.io.IOException - -/** - * Analyzes and extracts default values from constructor parameters. - */ -internal object DefaultValueAnalyzer { - private val MATH_CONSTANTS = setOf("PI", "E") - private val MATH_FUNCTIONS = setOf( - "sin", "cos", "tan", "asin", "acos", "atan", "atan2", - "sinh", "cosh", "tanh", "exp", "log", "log10", "sqrt", "abs", "ceil", "floor", - "round", "max", "min", "pow", - ) - private val BUILTIN_TYPES = setOf("Double", "Int", "Long", "Float", "String", "Boolean", "List", "Map", "Set") - - /** - * Extracts default values for all parameters that have them. - * - * @param remainingParams The parameters to extract default values from - * @param classDecl The class declaration (unused, kept for API compatibility) - * @return List of default value strings, null for parameters without defaults - */ - @Suppress("UNUSED_PARAMETER") - fun extractAllDefaultValues(remainingParams: List, classDecl: KSClassDeclaration): List = - remainingParams.mapNotNull { param -> - if (param.hasDefault) { - tryExtractDefaultFromSource(param) - } else { - null - } - } - - /** - * Extracts import statements needed for default value expressions. - * - * @param defaultValues List of default value strings - * @param classDecl The class declaration to analyze imports from - * @return Set of import statements needed - */ - fun extractNeededImportsFromDefaults(defaultValues: List, classDecl: KSClassDeclaration): Set { - val neededImports = mutableSetOf() - val defaultValueText = defaultValues.joinToString(" ") - val sourceImports = getSourceFileImports(classDecl) - neededImports.addAll(extractIdentifierImports(defaultValueText, sourceImports)) - return neededImports - } - - private fun extractIdentifierImports(defaultValueText: String, sourceImports: List): Set { - val neededImports = mutableSetOf() - // Use regex to find potential class/function identifiers so we can detect missing imports. - val identifierPattern = Regex("""\b([A-Z][a-zA-Z0-9]*)\b""") - val matches = identifierPattern.findAll(defaultValueText) - for (match in matches) { - val identifier = match.groupValues[1] - if (!(identifier in MATH_CONSTANTS || identifier in MATH_FUNCTIONS || identifier in BUILTIN_TYPES)) { - val qualifiedPattern = Regex("""\w+\.$identifier\b""") - if (!qualifiedPattern.containsMatchIn(defaultValueText)) { - addImportIfNeeded(identifier, defaultValueText, sourceImports, null, neededImports) - } - } - } - return neededImports - } - - private fun addImportIfNeeded( - identifier: String, - defaultValueText: String, - sourceImports: List, - defaultPackage: String?, - neededImports: MutableSet, - ) { - val pattern = Regex("""\b$identifier\b""") - if (pattern.containsMatchIn(defaultValueText)) { - val qualifiedPattern = Regex("""\w+\.$identifier""") - if (!qualifiedPattern.containsMatchIn(defaultValueText)) { - val import = findImportForIdentifier(identifier, sourceImports, defaultPackage) - if (import != null) { - neededImports.add(import) - } - } - } - } - - private fun getSourceFileImports(classDecl: KSClassDeclaration): List = try { - val file = classDecl.containingFile - if (file != null) { - val filePath = file.filePath - run { - val sourceCode = File(filePath).readText() - val importPattern = Regex("""^import\s+(.+)$""", RegexOption.MULTILINE) - importPattern.findAll(sourceCode).map { it.groupValues[1] }.toList() - } - } else { - emptyList() - } - } catch (e: IOException) { - throw IllegalStateException("Failed to read source file imports", e) - } - - private fun findImportForIdentifier( - identifier: String, - sourceImports: List, - defaultPackage: String?, - ): String? { - val explicitImport = sourceImports.find { it.endsWith(".$identifier") } - if (explicitImport != null) { - return "import $explicitImport" - } - return if (defaultPackage != null) { - "import $defaultPackage.$identifier" - } else { - null - } - } - - /** - * Attempts to extract a default value from the source code for a parameter. - * - * @param param The parameter to extract the default value for - * @return The default value string, or null if not found or extraction fails - */ - @Suppress("SwallowedException") - fun tryExtractDefaultFromSource(param: KSValueParameter): String? = try { - extractDefaultValueFromFile(param) - } catch (e: IOException) { - null - } - - private fun extractDefaultValueFromFile(param: KSValueParameter): String? { - val extractionData = prepareExtractionData(param) ?: return null - val defaultValue = extractBalancedExpression(extractionData.sourceCode, extractionData.startIndex) - val trimmed = defaultValue?.trim()?.takeIf { it.isNotEmpty() && !it.contains("\n") } - val result = getDefaultValueResult(trimmed, param, extractionData.sourceCode) - return result?.let { qualifyMathIdentifiers(it) } - } - - private fun getDefaultValueResult(trimmed: String?, param: KSValueParameter, sourceCode: String): String? { - if (trimmed != null) { - return trimmed - } - return extractDefaultValueFromParam(param, sourceCode) - } - - private fun extractDefaultValueFromParam(param: KSValueParameter, sourceCode: String): String? { - if (!param.hasDefault) { - return null - } - val paramName = param.name?.asString() - return paramName?.let { tryExtractSimpleDefault(sourceCode, it) } - } - - private fun qualifyMathIdentifiers(defaultValue: String): String { - val replacements = mutableListOf>() - replacements.addAll(findConstantReplacements(defaultValue)) - replacements.addAll(findFunctionReplacements(defaultValue)) - if (replacements.isEmpty()) { - return defaultValue - } - return applyReplacements(defaultValue, replacements) - } - - private fun findConstantReplacements(defaultValue: String): List> = - findMathReplacements(defaultValue, MATH_CONSTANTS) { identifier -> """\b$identifier\b""" } - - private fun findFunctionReplacements(defaultValue: String): List> = - findMathReplacements(defaultValue, MATH_FUNCTIONS) { identifier -> """\b$identifier\s*\(""" } - - private fun findMathReplacements( - defaultValue: String, - identifiers: Set, - patternBuilder: (String) -> String, - ): List> { - val replacements = mutableListOf>() - // Patterns above match both qualified and - // unqualified usages so we only rewrite the unqualified ones. - for (identifier in identifiers) { - val patternStr = patternBuilder(identifier) - val pattern = Regex(patternStr) - val qualifiedPattern = Regex("""\w+\.""" + patternStr.removePrefix("""\b""")) - if (pattern.containsMatchIn(defaultValue) && !qualifiedPattern.containsMatchIn(defaultValue)) { - pattern.findAll(defaultValue).forEach { match -> - if (!isQualifiedBefore(defaultValue, match.range.first)) { - replacements.add(match.range to "kotlin.math.${match.value}") - } - } - } - } - return replacements - } - - private fun isQualifiedBefore(defaultValue: String, index: Int): Boolean { - val before = defaultValue.take(index) - return before.endsWith(".") || before.endsWith("::") - } - - private fun applyReplacements(defaultValue: String, replacements: List>): String { - val sortedReplacements = replacements.sortedByDescending { it.first.first } - var result = defaultValue - for ((range, replacement) in sortedReplacements) { - result = result.replaceRange(range, replacement) - } - return result - } - - // Fallback regex-based extractor when the AST information is not enough. - // KSP doesn’t always expose the default-value expression - // it parsed, especially when the parameter belongs to a library or - // comes from metadata where the AST node isn’t available, - // we can’t rely solely on the AST-based extractor. - // In those cases we still want to keep generating the literal default - // (for imports, signatures, etc.) - private fun tryExtractSimpleDefault(sourceCode: String, paramName: String): String? { - val escapedName = Regex.escape(paramName) - val modifierPattern = """(?:private\s+|public\s+|protected\s+|internal\s+)?""" - val valVarPattern = """(?:val\s+|var\s+)?""" - val typePattern = """[^=,)]+""" - val valuePattern = """([^,\n)]+)""" - val patternWithModifiers = Regex( - """$modifierPattern$valVarPattern$escapedName\s*:\s*$typePattern=\s*$valuePattern""", - RegexOption.MULTILINE, - ) - val patternSimple = Regex( - """$escapedName\s*:\s*$typePattern=\s*$valuePattern""", - RegexOption.MULTILINE, - ) - val patterns = listOf(patternWithModifiers, patternSimple) - for (pattern in patterns) { - val match = pattern.find(sourceCode) - if (match != null && match.groupValues.size > 1) { - val value = match.groupValues[1].trim().trimEnd(',', ')') - if (value.isNotEmpty()) { - return value - } - } - } - return null - } - - private data class ExtractionData(val sourceCode: String, val startIndex: Int) - - private fun prepareExtractionData(param: KSValueParameter): ExtractionData? { - val validationResult = validateExtractionPrerequisites(param) ?: return null - val startIndex = findParameterDefaultStart(validationResult.sourceCode, validationResult.paramName) - return if (startIndex != null) { - ExtractionData(validationResult.sourceCode, startIndex) - } else { - null - } - } - - private data class ValidationResult(val sourceCode: String, val paramName: String) - - private fun validateExtractionPrerequisites(param: KSValueParameter): ValidationResult? { - val file = param.containingFile - val paramName = param.name?.asString() - return if (file != null && paramName != null) { - readSourceFile(file.filePath)?.let { ValidationResult(it, paramName) } - } else { - null - } - } - - @Suppress("SwallowedException") - private fun readSourceFile(filePath: String): String? = try { - File(filePath).readText() - } catch (e: IOException) { - null - } - - private fun findParameterDefaultStart(sourceCode: String, paramName: String): Int? { - val escapedName = Regex.escape(paramName) - val pattern = Regex( - """(?:private\s+|public\s+|protected\s+|internal\s+)?(?:val\s+|var\s+)?$escapedName\s*:\s*[^=,)]+=\s*""", - RegexOption.MULTILINE, - ) - val match = pattern.find(sourceCode) ?: return null - return match.range.last + 1 - } - - private fun extractBalancedExpression(sourceCode: String, startIndex: Int): String? { - if (startIndex >= sourceCode.length) return null - val state = ExtractionState(startIndex) - val result = StringBuilder() - while (state.index < sourceCode.length) { - val char = sourceCode[state.index] - val shouldContinue = processCharacter(char, sourceCode, state, result) - if (!shouldContinue) { - break - } - state.index++ - } - return result.toString().trim().takeIf { it.isNotEmpty() } - } - - private data class ExtractionState( - var index: Int, - var depth: Int = 0, - var inString: Boolean = false, - var stringChar: Char? = null, - val bracketStack: MutableList = mutableListOf(), - ) - - private fun processCharacter( - char: Char, - sourceCode: String, - state: ExtractionState, - result: StringBuilder, - ): Boolean = when { - handleStringStart(char, state, result) -> true - handleStringEnd(char, sourceCode, state, result) -> true - state.inString -> { - result.append(char) - true - } - handleOpeningBracket(char, state, result) -> true - handleClosingBracket(char, state, result) -> false - handleParameterSeparator(char, state) -> false - else -> { - result.append(char) - true - } - } - - private fun handleStringStart(char: Char, state: ExtractionState, result: StringBuilder): Boolean { - if (!state.inString && (char == '"' || char == '\'')) { - state.inString = true - state.stringChar = char - result.append(char) - return true - } - return false - } - - private fun handleStringEnd( - char: Char, - sourceCode: String, - state: ExtractionState, - result: StringBuilder, - ): Boolean { - if (!state.inString || char != state.stringChar) { - return false - } - val isEscaped = state.index > 0 && sourceCode[state.index - 1] == '\\' - return if (!isEscaped) { - state.inString = false - state.stringChar = null - result.append(char) - true - } else { - false - } - } - - private fun handleOpeningBracket(char: Char, state: ExtractionState, result: StringBuilder): Boolean { - val bracketType = when (char) { - '(' -> '(' - '[' -> '[' - '{' -> '{' - else -> return false - } - state.depth++ - state.bracketStack.add(bracketType) - result.append(char) - return true - } - - private fun handleClosingBracket(char: Char, state: ExtractionState, result: StringBuilder): Boolean { - if (state.depth == 0) { - return true - } - val matchingBracket = when (char) { - ')' -> '(' - ']' -> '[' - '}' -> '{' - else -> null - } - val isValidMatch = matchingBracket != null && - state.bracketStack.isNotEmpty() && - state.bracketStack.last() == matchingBracket - return if (isValidMatch) { - state.bracketStack.removeAt(state.bracketStack.size - 1) - state.depth-- - result.append(char) - false - } else { - true - } - } - - private fun handleParameterSeparator(char: Char, state: ExtractionState): Boolean = char == ',' && state.depth == 0 -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index dd5888c551..5350ed6964 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -11,18 +11,10 @@ import com.google.devtools.ksp.processing.SymbolProcessor import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSType -import com.google.devtools.ksp.symbol.KSValueParameter import com.google.devtools.ksp.validate -import findConstructor import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL -import it.unibo.alchemist.boundary.dsl.processor.data.ConstructorInfo -import it.unibo.alchemist.boundary.dsl.processor.data.GenerationContext import it.unibo.alchemist.boundary.dsl.processor.data.InjectableConstructor -import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext -import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType -import it.unibo.alchemist.boundary.dsl.processor.data.TypeParameterInfo import it.unibo.alchemist.boundary.dsl.processor.extensions.asString -import it.unibo.alchemist.boundary.dsl.processor.extensions.isInjectable import it.unibo.alchemist.boundary.dsl.processor.extensions.nameOrTypeName import it.unibo.alchemist.boundary.dsl.processor.extensions.typeName import it.unibo.alchemist.core.Simulation @@ -34,7 +26,7 @@ import it.unibo.alchemist.model.Reaction import it.unibo.alchemist.model.TimeDistribution import java.io.PrintWriter import java.nio.charset.StandardCharsets -import parameterTypes +import org.apache.commons.math3.random.RandomGenerator /** Symbol processor that emits DSL helpers for `@AlchemistKotlinDSL` classes. */ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) : SymbolProcessor { @@ -70,7 +62,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val private fun processClass(classDeclaration: KSClassDeclaration) { logger.dslInfo("Processing class ${classDeclaration.simpleName.asString()}") logger.dslInfo("Class qualified name: ${classDeclaration.qualifiedName?.asString()}") - val injectableTypes = injectableTypes() val file = codeGenerator.createNewFile( dependencies = classDeclaration.containingFile ?.let { Dependencies(false, it) } @@ -84,67 +75,74 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val writer.println("package ${classDeclaration.packageName.asString()}") writer.println() val functionName = classDeclaration.simpleName.asString().replaceFirstChar { it.lowercaseChar() } - classDeclaration.getConstructors() + val injectableConstructors = classDeclaration.getConstructors() .filter { it.isPublic() } .mapNotNull { InjectableConstructor(it) } - .forEach { (constructor, injectableParams, preservedParams) -> - val context = injectableParams.joinToString(prefix = "context(", postfix = ")") { param -> - "${param.nameOrTypeName()}: ${param.type.asString()}" - } - writer.println(context) - val typeParameters = constructor.typeParameters.takeIf { it.isNotEmpty() } - ?.joinToString(prefix = "<", postfix = "> ") { - buildString { - if (it.isReified) { - append("reified ") - } - append(it.name.asString()) - } - } - .orEmpty() - val parameters = preservedParams.joinToString(separator = NEWLINE_INDENT) { parameter -> + .toList() + if (injectableConstructors.isEmpty()) { + logger.warn( + "No injectable constructors, ${AlchemistKotlinDSL::class.qualifiedName} will have no effect.", + classDeclaration, + ) + } + injectableConstructors.forEach { (constructor, injectableParams, preservedParams) -> + val context = injectableParams.joinToString(prefix = "context(", postfix = ")") { param -> + "${param.nameOrTypeName()}: ${param.type.asString()}" + } + writer.println(context) + val typeParameters = constructor.typeParameters.takeIf { it.isNotEmpty() } + ?.joinToString(prefix = "<", postfix = "> ") { typeArgument -> buildString { - if (parameter.isCrossInline) { - append("crossinline ") - } - if (parameter.isNoInline) { - append("noinline ") - } - if (parameter.isVararg) { - append("vararg ") + if (typeArgument.isReified) { + append("reified ") } - append( - "${parameter.name?.asString()}: ${parameter.type.asString()}", - ) + append(typeArgument.name.asString()) } } - val whereClause = constructor.typeParameters - .flatMap { typeParam -> - typeParam.bounds.map { bound -> - "${typeParam.simpleName.asString()} : ${bound.asString()}" - } + .orEmpty() + val parameters = preservedParams.joinToString(separator = NEWLINE_INDENT) { parameter -> + buildString { + if (parameter.isCrossInline) { + append("crossinline ") } - .takeIf { it.isNotEmpty() } - ?.joinToString(separator = NEWLINE_INDENT, prefix = "where\n ", postfix = "\n") - .orEmpty() - val arguments = constructor.parameters.joinToString(NEWLINE_INDENT) { - buildString { - if (it.isVararg) { - append("*") - } - append(it.nameOrTypeName()) + if (parameter.isNoInline) { + append("noinline ") + } + if (parameter.isVararg) { + append("vararg ") } + append( + "${parameter.name?.asString()}: ${parameter.type.asString()}", + ) } - writer.println( - """ - |fun $typeParameters$functionName( - | $parameters - |) $whereClause= ${classDeclaration.typeName}( - | $arguments - |) - """.trimMargin(), - ) } + val whereClause = constructor.typeParameters + .flatMap { typeParam -> + typeParam.bounds.map { bound -> + "${typeParam.simpleName.asString()} : ${bound.asString()}" + } + } + .takeIf { it.isNotEmpty() } + ?.joinToString(separator = NEWLINE_INDENT, prefix = "where\n ", postfix = "\n") + .orEmpty() + val arguments = constructor.parameters.joinToString(NEWLINE_INDENT) { + buildString { + if (it.isVararg) { + append("*") + } + append(it.nameOrTypeName()) + } + } + writer.println( + """ + |fun $typeParameters$functionName( + | $parameters + |) $whereClause= ${classDeclaration.typeName}( + | $arguments + |) + """.trimMargin(), + ) + } } internal companion object { @@ -159,11 +157,10 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val resolver.getClassDeclarationByName>(), resolver.getClassDeclarationByName>(), resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName(), resolver.getClassDeclarationByName>(), resolver.getClassDeclarationByName>(), resolver.getClassDeclarationByName>(), - ) - .map { checkNotNull(it).asStarProjectedType() } - .toSet() + ).map { checkNotNull(it).asStarProjectedType() }.toSet() } } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt deleted file mode 100644 index 17a545e5be..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/FunctionGenerator.kt +++ /dev/null @@ -1,177 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSTypeReference -import com.google.devtools.ksp.symbol.KSValueParameter -import it.unibo.alchemist.boundary.dsl.processor.data.ConstructorInfo -import it.unibo.alchemist.boundary.dsl.processor.data.InjectionContext -import it.unibo.alchemist.boundary.dsl.processor.data.TypeParameterInfo - -/** Emits the signature, call site, and accessor for generated DSL helpers. */ -internal object FunctionGenerator { - /** Builds the helper function signature including context and receiver parts. */ - fun buildFunctionSignature( - functionName: String, - className: String, - typeParams: TypeParameterInfo, - constructorInfo: ConstructorInfo, - injectedParams: List>, - contextType: ContextType, - ): String { - val (finalTypeParamNames, finalTypeParamBounds) = TypeParameterHandler.prepareTypeParams( - typeParams.names, - typeParams.bounds, - injectedParams, - typeParams.classTypeParamBounds, - ) - - val functionTypeParamString = TypeParameterHandler.buildTypeParamString(finalTypeParamBounds) - val returnType = TypeParameterHandler.buildReturnType(className, typeParams.classTypeParamNames) - val contextPart = buildContextPart(injectedParams, contextType, finalTypeParamNames, finalTypeParamBounds) - val functionParams = buildFunctionParams( - constructorInfo.remainingParams, - constructorInfo.paramNames, - constructorInfo.paramTypes, - ) - val receiverPart = buildReceiverPart(injectedParams, contextType) - return "${contextPart}fun$functionTypeParamString $receiverPart$functionName$functionParams: $returnType =" - } - - // Build the context receiver only when injections exist so the generated function can require ctx. - private fun buildContextPart( - injectedParams: List>, - contextType: ContextType, - typeParamNames: List, - typeParamBounds: List, - ): String { - if (injectedParams.isEmpty()) { - return "" - } - val (tParam, pParam) = TypeParameterHandler.findTAndPParams(typeParamNames, typeParamBounds) - val pVariance = extractVarianceFromBound(pParam, typeParamBounds) - val pWithVariance = if (pVariance.isNotEmpty()) "$pVariance $pParam" else pParam - val contextTypeName = when (contextType) { - ContextType.SIMULATION_CONTEXT -> - "${ProcessorConfig.ContextTypes.SIMULATION_CONTEXT}<$tParam, $pWithVariance>" - ContextType.EXPORTER_CONTEXT -> - "${ProcessorConfig.ContextTypes.EXPORTER_CONTEXT}<$tParam, $pWithVariance>" - ContextType.GLOBAL_PROGRAMS_CONTEXT -> - "${ProcessorConfig.ContextTypes.GLOBAL_PROGRAMS_CONTEXT}<$tParam, $pWithVariance>" - ContextType.OUTPUT_MONITORS_CONTEXT -> - "${ProcessorConfig.ContextTypes.OUTPUT_MONITORS_CONTEXT}<$tParam, $pWithVariance>" - ContextType.TERMINATORS_CONTEXT -> - "${ProcessorConfig.ContextTypes.TERMINATORS_CONTEXT}<$tParam, $pWithVariance>" - ContextType.DEPLOYMENTS_CONTEXT -> - "${ProcessorConfig.ContextTypes.DEPLOYMENTS_CONTEXT}<$tParam, $pWithVariance>" - ContextType.DEPLOYMENT_CONTEXT -> - "${ProcessorConfig.ContextTypes.DEPLOYMENT_CONTEXT}<$tParam, $pWithVariance>" - ContextType.PROGRAM_CONTEXT -> "${ProcessorConfig.ContextTypes.PROGRAM_CONTEXT}<$tParam, $pWithVariance>" - ContextType.PROPERTY_CONTEXT -> "${ProcessorConfig.ContextTypes.PROPERTY_CONTEXT}<$tParam, $pWithVariance>" - } - return "context(ctx: $contextTypeName) " - } - - /** Reads the variance annotation (in/out) declared for a type parameter bound. */ - fun extractVarianceFromBound(paramName: String, typeParamBounds: List): String { - val paramIndex = typeParamBounds.indexOfFirst { it.startsWith("$paramName:") } - if (paramIndex < 0) { - return "" - } - val bound = typeParamBounds[paramIndex] - val boundPart = bound.substringAfter(":", "").trim() - return extractVarianceFromBoundPart(paramName, boundPart) - } - - private fun extractVarianceFromBoundPart(paramName: String, boundPart: String): String { - val escapedParamName = Regex.escape(paramName) - val outPattern = Regex("""""") - val inPattern = Regex("""""") - return when { - outPattern.containsMatchIn(boundPart) || boundPart.startsWith("out ") -> "out" - inPattern.containsMatchIn(boundPart) || boundPart.startsWith("in ") -> "in" - else -> "" - } - } - - /** Returns the parameter list string for the remaining constructor arguments. */ - fun buildFunctionParams( - remainingParams: List, - paramNames: List, - paramTypes: List, - ): String { - val regularParams = remainingParams.mapIndexed { idx, param -> - val name = paramNames[idx] - val type = paramTypes[idx] - val varargKeyword = if (param.isVararg) "vararg " else "" - val defaultValue = extractDefaultValue(param) - "$varargKeyword$name: $type$defaultValue" - } - val regularParamsPart = regularParams.joinToString(", ") - return if (regularParamsPart.isEmpty()) { - "()" - } else { - "($regularParamsPart)" - } - } - - private const val EMPTY_RECEIVER = "" - private fun buildReceiverPart( - @Suppress("UNUSED_PARAMETER") injectedParams: List>, - @Suppress("UNUSED_PARAMETER") contextType: ContextType, - ): String = EMPTY_RECEIVER - - /** Delegates to [ConstructorParamBuilder] to build argument expressions. */ - fun buildConstructorParams( - constructorInfo: ConstructorInfo, - injectionContext: InjectionContext, - typeParamNames: List, - ): List = ConstructorParamBuilder.buildConstructorParams( - constructorInfo, - injectionContext, - typeParamNames, - ) - - /** Formats the constructor invocation using the resolved parameters. */ - fun buildConstructorCall( - className: String, - typeParamNames: List, - constructorParams: List, - classTypeParamNames: List = typeParamNames, - ): String { - val constructorTypeArgs = if (classTypeParamNames.isNotEmpty()) { - "<${classTypeParamNames.joinToString(", ")}>" - } else { - "" - } - return "$className$constructorTypeArgs(${constructorParams.joinToString(", ")})" - } - - private fun extractDefaultValue(param: KSValueParameter): String { - if (!param.hasDefault) { - return "" - } - val defaultValueExpr = DefaultValueAnalyzer.tryExtractDefaultFromSource(param) - return defaultValueExpr?.let { " = $it" }.orEmpty() - } - - /** Computes which type parameters the referenced type requires beyond the ones already known. */ - fun collectNeededTypeParams(typeRef: KSTypeReference, existingTypeParamNames: List): Set = - TypeParameterHandler.collectNeededTypeParams(typeRef, existingTypeParamNames) - - /** Builds the context parameter type for the injected argument expression. */ - fun buildContextParamType( - typeRef: KSTypeReference, - typeParamNames: MutableList, - typeParamBounds: MutableList, - ): String = TypeArgumentProcessor.buildContextParamType(typeRef, typeParamNames, typeParamBounds) - - /** Builds property-context-specific constructor arguments. */ - fun buildConstructorParamsForPropertyContext( - constructorInfo: ConstructorInfo, - injectionContext: InjectionContext, - typeParamNames: List, - ): List = ConstructorParamBuilder.buildConstructorParamsForPropertyContext( - constructorInfo, - injectionContext, - typeParamNames, - ) -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt deleted file mode 100644 index 439ee35747..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ImportManager.kt +++ /dev/null @@ -1,22 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSClassDeclaration -import java.io.PrintWriter - -/** - * Manages writing import statements for generated DSL code. - */ -internal object ImportManager { - /** - * Writes all necessary import statements to the generated code file. - * - * @param writer The PrintWriter to write imports to - * @param defaultValues Default value expressions that may require imports - * @param classDecl The class declaration being processed - */ - fun writeImports(writer: PrintWriter, defaultValues: List, classDecl: KSClassDeclaration) { - val neededImports = DefaultValueAnalyzer.extractNeededImportsFromDefaults(defaultValues, classDecl) - neededImports.forEach { writer.println(it) } - writer.println() - } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt deleted file mode 100644 index c058cb1444..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ParameterInjector.kt +++ /dev/null @@ -1,222 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.getClassDeclarationByName -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.symbol.KSType -import com.google.devtools.ksp.symbol.KSValueParameter -import it.unibo.alchemist.boundary.dsl.processor.data.InjectionType -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.Reaction -import it.unibo.alchemist.model.TimeDistribution -import org.apache.commons.math3.random.RandomGenerator - -/** - * Information about a parameter injection. - * - * @property type The type of injection - * @property index The parameter index - * @property inject Whether to inject this parameter - */ -internal data class InjectionInfo( - /** The type of injection. */ - val type: InjectionType, - /** The parameter index. */ - val index: Int, - /** Whether to inject this parameter. */ - val inject: Boolean, -) - -/** - * Finds and manages parameter injection indices for context-aware DSL generation. - */ -internal object ParameterInjector { - /** - * Finds indices of parameters that can be injected from context. - * - * @param parameters The list of constructor parameters to analyze - * @return A map from injection type to parameter index - */ - context(resolver: Resolver) - internal fun findInjectionIndices(parameters: List): Map { - val indices = mutableMapOf() - parameters.forEachIndexed { index, param -> - val resolved = param.type.resolve() - val declaration = resolved.declaration - val qualifiedName = declaration.qualifiedName?.asString().orEmpty() - val simpleName = declaration.simpleName.asString() - when { - resolved.isSubtypeOf>() -> indices[InjectionType.ENVIRONMENT] = index - resolved.isSubtypeOf() -> indices[InjectionType.GENERATOR] = index - resolved.isSubtypeOf>() -> indices[InjectionType.INCARNATION] = index - resolved.isSubtypeOf>() -> indices[InjectionType.NODE] = index - resolved.isSubtypeOf>() -> indices[InjectionType.REACTION] = index - resolved.isSubtypeOf>() -> indices[InjectionType.TIMEDISTRIBUTION] = index - isFilterType(resolved, simpleName, qualifiedName) -> indices[InjectionType.FILTER] = index - } - } - return indices - } - - context(resolver: Resolver) - private inline fun KSType.isSubtypeOf(): Boolean = - checkNotNull(resolver.getClassDeclarationByName()).asStarProjectedType().isAssignableFrom(this) - - private fun isFilterType(type: KSType, simpleName: String, qualifiedName: String): Boolean { - val effectiveType = type.makeNotNullable() - val effectiveDeclaration = effectiveType.declaration - val effectiveQualifiedName = effectiveDeclaration.qualifiedName?.asString().orEmpty() - val effectiveSimpleName = effectiveDeclaration.simpleName.asString() - if (effectiveSimpleName != "PositionBasedFilter" && !effectiveQualifiedName.endsWith(".PositionBasedFilter")) { - return false - } - return TypeHierarchyChecker.isAssignableTo(effectiveType, ProcessorConfig.POSITION_BASED_FILTER_TYPE) || - effectiveQualifiedName == ProcessorConfig.POSITION_BASED_FILTER_TYPE || - effectiveQualifiedName.startsWith("${ProcessorConfig.POSITION_BASED_FILTER_TYPE}.") - } - - /** - * Parses a scope string to a ContextType enum value. - * Supports both enum names and class names (e.g., "DEPLOYMENT" or "DEPLOYMENTS_CONTEXT"). - * - * @param scope The scope string - * @return The corresponding ContextType, or null if the scope is invalid or empty - */ - fun parseScope(scope: String?): ContextType? { - if (scope.isNullOrBlank()) { - return null - } - // accept both versions or the scope - return when (val upperScope = scope.uppercase()) { - "SIMULATION", "SIMULATION_CONTEXT" -> ContextType.SIMULATION_CONTEXT - "EXPORTER", "EXPORTER_CONTEXT" -> ContextType.EXPORTER_CONTEXT - "GLOBAL_PROGRAMS", "GLOBAL_PROGRAMS_CONTEXT" -> ContextType.GLOBAL_PROGRAMS_CONTEXT - "OUTPUT_MONITORS", "OUTPUT_MONITORS_CONTEXT" -> ContextType.OUTPUT_MONITORS_CONTEXT - "TERMINATORS", "TERMINATORS_CONTEXT" -> ContextType.TERMINATORS_CONTEXT - "DEPLOYMENT", "DEPLOYMENTS_CONTEXT" -> ContextType.DEPLOYMENTS_CONTEXT - "DEPLOYMENT_CONTEXT" -> ContextType.DEPLOYMENT_CONTEXT - "PROGRAM", "PROGRAM_CONTEXT" -> ContextType.PROGRAM_CONTEXT - "PROPERTY", "PROPERTY_CONTEXT" -> ContextType.PROPERTY_CONTEXT - else -> { - @Suppress("SwallowedException") - try { - ContextType.valueOf(upperScope) - } catch (e: IllegalArgumentException) { - null - } - } - } - } - - /** - * Determines the context type based on injection indices and annotation values. - * If a manual scope is provided in the annotation, it takes precedence over automatic detection. - * - * @param injectionIndices Map of injection types to parameter indices - * @return The determined context type - */ - // Determine which context is active by checking manual overrides first, then injection mix. - fun determineContextType(injectionIndices: Map): ContextType = - determineContextTypeFromInjections(injectionIndices) - - private fun determineContextTypeFromInjections(injectionIndices: Map): ContextType = when { - injectionIndices.containsKey(InjectionType.FILTER) -> ContextType.DEPLOYMENT_CONTEXT - hasProgramContextInjections(injectionIndices) -> ContextType.PROGRAM_CONTEXT - else -> determineDeploymentOrSimulationContext(injectionIndices) - } - - private fun hasProgramContextInjections(injectionIndices: Map): Boolean { - val hasNode = injectionIndices.containsKey(InjectionType.NODE) - val hasReaction = injectionIndices.containsKey(InjectionType.REACTION) - val hasTimeDistribution = injectionIndices.containsKey(InjectionType.TIMEDISTRIBUTION) - return hasNode || hasReaction || hasTimeDistribution - } - - private fun determineDeploymentOrSimulationContext(injectionIndices: Map): ContextType { - val hasEnvironment = injectionIndices.containsKey(InjectionType.ENVIRONMENT) - val hasGenerator = injectionIndices.containsKey(InjectionType.GENERATOR) - val hasIncarnation = injectionIndices.containsKey(InjectionType.INCARNATION) - val injectedCount = listOf(hasEnvironment, hasGenerator, hasIncarnation).count { it } - return if (injectedCount == 1 && (hasIncarnation || hasEnvironment)) { - ContextType.SIMULATION_CONTEXT - } else { - ContextType.DEPLOYMENTS_CONTEXT - } - } - - /** - * Gets the set of parameter indices that should be skipped (injected from context). - * - * @param injectionIndices Map of injection types to parameter indices - * @param contextType The context type to determine which parameters can be injected - * @return Set of parameter indices to skip - */ - fun getInjectionParams(injectionIndices: Map, contextType: ContextType): Set { - val paramsToSkip = mutableSetOf() - if (isInjectionTypeAvailable(InjectionType.ENVIRONMENT, contextType)) { - addInjectionParamIfEnabled( - InjectionType.ENVIRONMENT, - injectionIndices, - paramsToSkip, - ) - } - - if (isInjectionTypeAvailable(InjectionType.GENERATOR, contextType)) { - addInjectionParamIfEnabled( - InjectionType.GENERATOR, - injectionIndices, - paramsToSkip, - ) - } - - if (isInjectionTypeAvailable(InjectionType.INCARNATION, contextType)) { - addInjectionParamIfEnabled( - InjectionType.INCARNATION, - injectionIndices, - paramsToSkip, - ) - } - - if (isInjectionTypeAvailable(InjectionType.NODE, contextType)) { - addInjectionParamIfEnabled( - InjectionType.NODE, - injectionIndices, - paramsToSkip, - ) - } - - if (isInjectionTypeAvailable(InjectionType.REACTION, contextType)) { - addInjectionParamIfEnabled( - InjectionType.REACTION, - injectionIndices, - paramsToSkip, - ) - } - if (isInjectionTypeAvailable(InjectionType.TIMEDISTRIBUTION, contextType)) { - injectionIndices[InjectionType.TIMEDISTRIBUTION]?.let { paramsToSkip.add(it) } - } - if (isInjectionTypeAvailable(InjectionType.FILTER, contextType)) { - injectionIndices[InjectionType.FILTER]?.let { paramsToSkip.add(it) } - } - return paramsToSkip - } - - @Suppress("SwallowedException") - private fun isInjectionTypeAvailable(injectionType: InjectionType, contextType: ContextType): Boolean = try { - ContextAccessor.getAccessor(injectionType, contextType) - true - } catch (e: IllegalArgumentException) { - false - } - - private fun addInjectionParamIfEnabled( - injectionType: InjectionType, - injectionIndices: Map, - paramsToSkip: MutableSet, - ) { - if (injectionIndices.containsKey(injectionType)) { - injectionIndices[injectionType]?.let { paramsToSkip.add(it) } - } - } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt deleted file mode 100644 index 20e0672163..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/ProcessorConfig.kt +++ /dev/null @@ -1,75 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -/** - * Configuration for the DSL processor, centralizing package names and type detection rules. - * This makes the processor more maintainable and allows for easier customization. - */ -internal object ProcessorConfig { - /** - * Base package for Alchemist model classes. - */ - const val MODEL_PACKAGE = "it.unibo.alchemist.model" - - /** - * Base package for Alchemist boundary DSL classes. - */ - const val DSL_PACKAGE = "it.unibo.alchemist.boundary.dsl" - - /** - * Package where generated code will be placed. - */ - const val GENERATED_PACKAGE = "$DSL_PACKAGE.generated" - - /** - * Package for DSL model classes (contexts). - */ - const val DSL_MODEL_PACKAGE = "$DSL_PACKAGE.model" - - /** - * Fully qualified name for the Position interface. - */ - const val POSITION_TYPE = "$MODEL_PACKAGE.Position" - - /** - * Fully qualified name for PositionBasedFilter interface. - */ - const val POSITION_BASED_FILTER_TYPE = "$MODEL_PACKAGE.PositionBasedFilter" - - /** - * Context type class names. - */ - object ContextTypes { - /** Fully qualified name for SimulationContext. */ - const val SIMULATION_CONTEXT = "$DSL_MODEL_PACKAGE.SimulationContext" - - /** Fully qualified name for ExporterContext. */ - const val EXPORTER_CONTEXT = "$DSL_MODEL_PACKAGE.ExporterContext" - - /** Fully qualified name for GlobalProgramsContext. */ - const val GLOBAL_PROGRAMS_CONTEXT = "$DSL_MODEL_PACKAGE.GlobalProgramsContext" - - /** Fully qualified name for OutputMonitorsContext. */ - const val OUTPUT_MONITORS_CONTEXT = "$DSL_MODEL_PACKAGE.OutputMonitorsContext" - - /** Fully qualified name for TerminatorsContext. */ - const val TERMINATORS_CONTEXT = "$DSL_MODEL_PACKAGE.TerminatorsContext" - - /** Fully qualified name for DeploymentsContext. */ - const val DEPLOYMENTS_CONTEXT = "$DSL_MODEL_PACKAGE.DeploymentsContext" - - /** Fully qualified name for DeploymentContext. */ - const val DEPLOYMENT_CONTEXT = "$DSL_MODEL_PACKAGE.DeploymentContext" - - /** Fully qualified name for ProgramsContext. */ - const val PROGRAMS_CONTEXT = "$DSL_MODEL_PACKAGE.ProgramsContext" - - /** Fully qualified name for ProgramContext. */ - const val PROGRAM_CONTEXT = "$DSL_MODEL_PACKAGE.ProgramContext" - - /** Fully qualified name for PropertiesContext. */ - const val PROPERTIES_CONTEXT = "$DSL_MODEL_PACKAGE.PropertiesContext" - - /** Fully qualified name for PropertyContext. */ - const val PROPERTY_CONTEXT = "$DSL_MODEL_PACKAGE.PropertyContext" - } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt deleted file mode 100644 index 1ea0b6b012..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeArgumentProcessor.kt +++ /dev/null @@ -1,199 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSDeclaration -import com.google.devtools.ksp.symbol.KSTypeAlias -import com.google.devtools.ksp.symbol.KSTypeArgument -import com.google.devtools.ksp.symbol.KSTypeParameter -import com.google.devtools.ksp.symbol.KSTypeReference -import com.google.devtools.ksp.symbol.Variance - -/** - * Processes type arguments for context parameters in DSL builder functions. - */ -internal object TypeArgumentProcessor { - /** - * Builds the type string for a context parameter, handling type arguments and bounds. - * - * @param typeRef The type reference to build from - * @param typeParamNames Mutable list of type parameter names (may be modified) - * @param typeParamBounds Mutable list of type parameter bounds (may be modified) - * @return The type string for the context parameter - */ - fun buildContextParamType( - typeRef: KSTypeReference, - typeParamNames: MutableList, - typeParamBounds: MutableList, - ): String { - val resolved = typeRef.resolve() - val declaration = resolved.declaration - val typeName = getTypeName(declaration) - val arguments = resolved.arguments - if (arguments.isEmpty()) { - return typeName - } - val declarationTypeParams = getDeclarationTypeParams(declaration) - // These are fallback names for wildcard/null arguments so we always generate valid type parameters. - val standardTypeParams = listOf("T", "U", "V", "W") - val indexState = IndexState(0, 0) - val typeArgs = arguments.joinToString(", ") { arg -> - processTypeArgument( - arg, - declarationTypeParams, - standardTypeParams, - typeParamNames, - typeParamBounds, - indexState, - ) - } - - return "$typeName<$typeArgs>" - } - - private data class IndexState(var nextStandardIndex: Int, var nextDeclParamIndex: Int) - - private fun getTypeName(declaration: KSDeclaration): String { - val qualifiedName = declaration.qualifiedName?.asString() - return if (!qualifiedName.isNullOrEmpty()) { - qualifiedName - } else { - declaration.simpleName.asString() - } - } - - private fun getDeclarationTypeParams(declaration: KSDeclaration): List = when (declaration) { - is KSClassDeclaration -> declaration.typeParameters - is KSTypeAlias -> declaration.typeParameters - else -> emptyList() - } - - private fun processTypeArgument( - arg: KSTypeArgument, - declarationTypeParams: List, - standardTypeParams: List, - typeParamNames: MutableList, - typeParamBounds: MutableList, - indexState: IndexState, - ): String = when { - arg.type == null || arg.variance == Variance.STAR -> { - val result = handleNullOrStarTypeArg( - declarationTypeParams, - standardTypeParams, - typeParamNames, - typeParamBounds, - indexState.nextDeclParamIndex, - indexState.nextStandardIndex, - ) - indexState.nextDeclParamIndex = result.second - indexState.nextStandardIndex = result.third - result.first - } - else -> processConcreteTypeArgument(arg, typeParamNames, typeParamBounds, standardTypeParams, indexState) - } - - private fun handleNullOrStarTypeArg( - declarationTypeParams: List, - standardTypeParams: List, - typeParamNames: MutableList, - typeParamBounds: MutableList, - nextDeclParamIndex: Int, - nextStandardIndex: Int, - ): Triple { - val (paramName, declParam) = if (nextDeclParamIndex < declarationTypeParams.size) { - val declParam = declarationTypeParams[nextDeclParamIndex] - declParam.name.asString() to declParam - } else if (nextStandardIndex < standardTypeParams.size) { - standardTypeParams[nextStandardIndex] to null - } else { - "T" to null - } - val newNextDeclParamIndex = if (nextDeclParamIndex < declarationTypeParams.size) { - nextDeclParamIndex + 1 - } else { - nextDeclParamIndex - } - val newNextStandardIndex = if (nextDeclParamIndex >= declarationTypeParams.size && - nextStandardIndex < standardTypeParams.size - ) { - nextStandardIndex + 1 - } else { - nextStandardIndex - } - if (!typeParamNames.contains(paramName)) { - typeParamNames.add(paramName) - val boundStr = if (declParam != null) { - val bounds = declParam.bounds.map { bound -> - TypeBoundProcessor.processBound(bound) - }.toList() - if (bounds.isNotEmpty()) { - "$paramName: ${bounds.joinToString(" & ")}" - } else { - paramName - } - } else { - paramName - } - typeParamBounds.add(boundStr) - } - return Triple(paramName, newNextDeclParamIndex, newNextStandardIndex) - } - - private fun processConcreteTypeArgument( - arg: KSTypeArgument, - typeParamNames: MutableList, - typeParamBounds: MutableList, - standardTypeParams: List, - indexState: IndexState, - ): String { - val argType = arg.type ?: return "T" - val argDecl = argType.resolve().declaration - return if (argDecl is KSTypeParameter) { - addTypeParameterIfNeeded(argDecl, typeParamNames, typeParamBounds) - argDecl.name.asString() - } else { - processExtractedType(argType, typeParamNames, standardTypeParams, indexState, typeParamBounds) - } - } - - private fun addTypeParameterIfNeeded( - argDecl: KSTypeParameter, - typeParamNames: MutableList, - typeParamBounds: MutableList, - ) { - val paramName = argDecl.name.asString() - if (!typeParamNames.contains(paramName)) { - typeParamNames.add(paramName) - val bounds = argDecl.bounds.map { TypeBoundProcessor.processBound(it) }.toList() - val boundStr = if (bounds.isNotEmpty()) { - "$paramName: ${bounds.joinToString(" & ")}" - } else { - paramName - } - typeParamBounds.add(boundStr) - } - } - - private fun processExtractedType( - typeRef: KSTypeReference, - typeParamNames: MutableList, - standardTypeParams: List, - indexState: IndexState, - typeParamBounds: MutableList, - ): String { - val extracted = TypeExtractor.extractTypeString(typeRef, typeParamNames) - return if (extracted.contains("*") || !typeParamNames.any { it in extracted }) { - val standardName = if (indexState.nextStandardIndex < standardTypeParams.size) { - standardTypeParams[indexState.nextStandardIndex++] - } else { - "T" - } - if (!typeParamNames.contains(standardName)) { - typeParamNames.add(standardName) - typeParamBounds.add(standardName) - } - standardName - } else { - extracted - } - } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt deleted file mode 100644 index 8a504768d2..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeBoundProcessor.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSTypeReference -import it.unibo.alchemist.boundary.dsl.processor.extensions.toStringWithGenerics - -/** - * Processes type bounds for type parameters, cleaning up internal Kotlin type representations. - */ -internal object TypeBoundProcessor { - /** - * Processes a type bound reference, cleaning up internal Kotlin type representations and variance annotations. - * - * @param bound The type reference to process - * @param classTypeParamNames List of class type parameter names to replace in the bound - * @return A cleaned string representation of the bound with fully qualified names - */ - fun processBound(bound: KSTypeReference, classTypeParamNames: List = emptyList()): String { - val resolved = bound.resolve() - val decl = resolved.declaration - val qualifiedName = decl.qualifiedName?.asString() - if (qualifiedName != null) { - val result = resolved.toStringWithGenerics(classTypeParamNames) - return replaceClassTypeParamReferences(result, classTypeParamNames) - } - val result = TypeExtractor.extractTypeString(bound, emptyList()) - return replaceClassTypeParamReferences(result, classTypeParamNames) - } -} - -// TODO: revise this function -internal fun replaceClassTypeParamReferences(boundStr: String, classTypeParamNames: List): String { - // Strip redundant qualification when the matcher references - // the same class-level type parameter - if (classTypeParamNames.isEmpty()) { - return boundStr - } - var result = boundStr - classTypeParamNames.forEach { paramName -> - val pattern = Regex("""\b[\w.]+\.$paramName\b""") - result = pattern.replace(result) { matchResult -> - val matched = matchResult.value - val prefix = matched.substringBefore(".$paramName") - if (prefix.contains(".")) { - paramName - } else { - matched - } - } - } - return result -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt deleted file mode 100644 index 6cd20afa27..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeExtractor.kt +++ /dev/null @@ -1,92 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSTypeParameter -import com.google.devtools.ksp.symbol.KSTypeReference -import com.google.devtools.ksp.symbol.KSValueParameter -import it.unibo.alchemist.boundary.dsl.processor.extensions.toStringWithGenerics - -/** - * Extracts type information from KSP symbols for code generation. - */ -internal object TypeExtractor { - /** - * Extracts type parameter names and bounds from a class declaration. - * - * @param classDecl The class declaration to extract type parameters from - * @return A pair of (type parameter names, type parameter bounds) - */ - fun extractTypeParameters(classDecl: KSClassDeclaration): Pair, List> { - val typeParameters = classDecl.typeParameters - val typeParamNames = typeParameters.map { it.name.asString() } - val typeParamBounds = typeParameters.map { typeParam -> - val bounds: List = typeParam.bounds.map { bound -> - TypeBoundProcessor.processBound(bound, typeParamNames) - }.toList() - if (bounds.isNotEmpty()) { - val boundStr = bounds.joinToString(" & ") - "${typeParam.name.asString()}: $boundStr" - } else { - typeParam.name.asString() - } - } - return typeParamNames to typeParamBounds - } - - /** - * Extracts a string representation of a type reference. - * - * @param typeRef The type reference to extract - * @param typeParamNames List of existing type parameter names for substitution - * @return A string representation of the type - */ - // Normalize a KSTypeReference into a printable string, respecting existing type parameter names. - fun extractTypeString(typeRef: KSTypeReference, typeParamNames: List = emptyList()): String { - val resolved = typeRef.resolve() - val declaration = resolved.declaration - if (declaration is KSTypeParameter) { - val paramName = declaration.name.asString() - if (typeParamNames.contains(paramName)) { - return paramName - } - } - return resolved.toStringWithGenerics(typeParamNames) - } - - /** - * Extracts type strings for a list of value parameters. - * - * @param remainingParams The parameters to extract types from - * @param typeParamNames List of existing type parameter names for substitution - * @return A list of type strings - */ - fun extractParamTypes( - remainingParams: List, - typeParamNames: List = emptyList(), - ): List = remainingParams.map { param -> - if (param.isVararg) { - val resolved = param.type.resolve() - val declaration = resolved.declaration - val qualifiedName = declaration.qualifiedName?.asString().orEmpty() - if (qualifiedName == "kotlin.Array" || qualifiedName == "Array") { - resolved.arguments.firstOrNull()?.type?.let { elementType -> - extractTypeString(elementType, typeParamNames) - } ?: extractTypeString(param.type, typeParamNames) - } else { - extractTypeString(param.type, typeParamNames) - } - } else { - extractTypeString(param.type, typeParamNames) - } - } - - /** - * Extracts parameter names from a list of value parameters. - * - * @param remainingParams The parameters to extract names from - * @return A list of parameter names - */ - fun extractParamNames(remainingParams: List): List = remainingParams.map { param -> - param.name?.asString() ?: "param${remainingParams.indexOf(param)}" - } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt deleted file mode 100644 index bd07bba118..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeHierarchyChecker.kt +++ /dev/null @@ -1,119 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSType -import com.google.devtools.ksp.symbol.KSTypeReference - -/** - * Checks type hierarchies using KSP's type resolution instead of string matching. - * This provides more accurate type detection by checking actual type relationships. - */ -internal object TypeHierarchyChecker { - /** - * Checks if a type implements or extends a target type by qualified name. - * - * @param type The type to check - * @param targetQualifiedName The fully qualified name of the target type - * @return True if the type implements or extends the target type - */ - fun isAssignableTo(type: KSType, targetQualifiedName: String): Boolean { - val declaration = type.declaration - val typeQualifiedName = declaration.qualifiedName?.asString() - if (typeQualifiedName == targetQualifiedName) { - return true - } - return declaration is KSClassDeclaration && checkSuperTypes(declaration, targetQualifiedName, mutableSetOf()) - } - - /** - * Checks if a type reference resolves to a type that implements or extends a target type. - * - * @param typeRef The type reference to check - * @param targetQualifiedName The fully qualified name of the target type - * @return True if the type implements or extends the target type - */ - @Suppress("SwallowedException", "TooGenericExceptionCaught") - fun isAssignableTo(typeRef: KSTypeReference, targetQualifiedName: String): Boolean = try { - val resolved = typeRef.resolve() - isAssignableTo(resolved, targetQualifiedName) - } catch (e: RuntimeException) { - false - } - - private fun checkSuperTypes( - classDecl: KSClassDeclaration, - targetQualifiedName: String, - visited: MutableSet, - ): Boolean { - val qualifiedName = classDecl.qualifiedName?.asString() ?: return false - return when (qualifiedName) { - in visited -> false - targetQualifiedName -> true - else -> { - visited.add(qualifiedName) - checkSuperTypesRecursive(classDecl, targetQualifiedName, visited) - } - } - } - - private fun checkSuperTypesRecursive( - classDecl: KSClassDeclaration, - targetQualifiedName: String, - visited: MutableSet, - ): Boolean { - val superTypes = classDecl.superTypes.toList() - for (superType in superTypes) { - if (checkSuperType(superType, targetQualifiedName, visited)) { - return true - } - } - return false - } - - @Suppress("SwallowedException", "TooGenericExceptionCaught") - private fun checkSuperType( - superType: KSTypeReference, - targetQualifiedName: String, - visited: MutableSet, - ): Boolean = try { - val resolved = superType.resolve() - val superDecl = resolved.declaration - val superQualifiedName = superDecl.qualifiedName?.asString() - superQualifiedName == targetQualifiedName || - (superDecl is KSClassDeclaration && checkSuperTypes(superDecl, targetQualifiedName, visited)) - } catch (e: RuntimeException) { - false - } - - /** - * Checks if a type's qualified name matches any of the provided patterns. - * Falls back to string matching when type hierarchy checking is not possible. - * - * @param type The type to check - * @param targetQualifiedNames Set of fully qualified names to match against - * @return True if the type matches any target name - */ - // Walk the inheritance tree to check for supertypes without relying on string heuristics. - fun matchesAny(type: KSType, targetQualifiedNames: Set): Boolean { - val declaration = type.declaration - val qualifiedName = declaration.qualifiedName?.asString() ?: return false - return targetQualifiedNames.contains(qualifiedName) || - targetQualifiedNames.any { targetName -> isAssignableTo(type, targetName) } - } - - /** - * Checks if a type's qualified name matches a pattern or is in a package. - * - * @param type The type to check - * @param targetQualifiedName The target qualified name - * @param packagePatterns Set of package patterns to check - * @return True if the type matches - */ - fun matchesTypeOrPackage(type: KSType, targetQualifiedName: String, packagePatterns: Set): Boolean { - val declaration = type.declaration - val qualifiedName = declaration.qualifiedName?.asString() ?: return false - return qualifiedName == targetQualifiedName || - isAssignableTo(type, targetQualifiedName) || - packagePatterns.any { pattern -> qualifiedName.startsWith(pattern) } - } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt deleted file mode 100644 index 829c43b722..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/TypeParameterHandler.kt +++ /dev/null @@ -1,203 +0,0 @@ -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSTypeArgument -import com.google.devtools.ksp.symbol.KSTypeParameter -import com.google.devtools.ksp.symbol.KSTypeReference -import com.google.devtools.ksp.symbol.Variance - -/** - * Handles type parameter preparation and manipulation for DSL builder functions. - */ -internal object TypeParameterHandler { - /** - * Prepares type parameters by adding T and P parameters if needed for injected parameters. - * - * @param typeParamNames Initial type parameter names - * @param typeParamBounds Initial type parameter bounds - * @param injectedParams List of injected parameter names and types - * @param classTypeParamBounds Type parameter bounds from the class declaration - * @return Pair of final type parameter names and bounds - */ - fun prepareTypeParams( - typeParamNames: List, - typeParamBounds: List, - injectedParams: List>, - classTypeParamBounds: List, - ): Pair, MutableList> { - val finalTypeParamNames = typeParamNames.toMutableList() - val finalTypeParamBounds = typeParamBounds.toMutableList() - if (injectedParams.isNotEmpty()) { - val (tParam, pParam) = findTAndPParams(typeParamNames, typeParamBounds) - addTParamIfNeeded(tParam, finalTypeParamNames, finalTypeParamBounds) - addPParamIfNeeded(pParam, finalTypeParamNames, finalTypeParamBounds, classTypeParamBounds) - } else if (typeParamNames.isEmpty() && classTypeParamBounds.isNotEmpty()) { - finalTypeParamNames.clear() - finalTypeParamBounds.clear() - classTypeParamBounds.forEachIndexed { index, bound -> - val paramName = if (bound.contains(":")) bound.substringBefore(":") else bound - finalTypeParamNames.add(paramName.trim()) - finalTypeParamBounds.add(bound) - } - } - return finalTypeParamNames to finalTypeParamBounds - } - - private fun addTParamIfNeeded( - tParam: String, - finalTypeParamNames: MutableList, - finalTypeParamBounds: MutableList, - ) { - val tIndex = finalTypeParamNames.indexOf(tParam) - if (tIndex >= 0) { - val existingTBound = finalTypeParamBounds.getOrNull(tIndex) - if (existingTBound != null && !existingTBound.contains(":")) { - finalTypeParamBounds[tIndex] = tParam - } - } else { - finalTypeParamNames.add(tParam) - val tBound = finalTypeParamBounds.find { it.startsWith("$tParam:") } ?: tParam - finalTypeParamBounds.add(tBound) - } - } - - private fun addPParamIfNeeded( - pParam: String, - finalTypeParamNames: MutableList, - finalTypeParamBounds: MutableList, - classTypeParamBounds: List, - ) { - val pIndex = finalTypeParamNames.indexOf(pParam) - val classPIndex = classTypeParamBounds.indexOfFirst { it.contains("Position") } - val expectedBound = if (classPIndex >= 0) { - val classBound = classTypeParamBounds[classPIndex] - if (classBound.contains(":")) { - val boundPart = classBound.substringAfter(":") - "$pParam:$boundPart" - } else { - "$pParam: ${ProcessorConfig.POSITION_TYPE}<$pParam>" - } - } else { - "$pParam: it.unibo.alchemist.model.Position<$pParam>" - } - if (pIndex >= 0) { - val existingBound = finalTypeParamBounds.getOrNull(pIndex) - if (existingBound == null || !existingBound.contains("Position") || existingBound != expectedBound) { - if (pIndex < finalTypeParamBounds.size) { - finalTypeParamBounds[pIndex] = expectedBound - } else { - finalTypeParamBounds.add(expectedBound) - } - } - } else { - finalTypeParamNames.add(pParam) - finalTypeParamBounds.add(expectedBound) - } - } - - /** - * Finds or determines the T and P type parameter names from the given lists. - * - * @param typeParamNames List of type parameter names - * @param typeParamBounds List of type parameter bounds - * @return Pair of (T parameter name, P parameter name) - */ - fun findTAndPParams(typeParamNames: List, typeParamBounds: List): Pair { - val pIndex = typeParamBounds.indexOfFirst { it.contains("Position") } - val pParam = if (pIndex >= 0 && pIndex < typeParamNames.size) { - typeParamNames[pIndex] - } else { - "P" - } - val tIndex = typeParamNames.indexOf("T") - val tParam = when { - tIndex >= 0 -> typeParamNames[tIndex] - pIndex == 0 && typeParamNames.size > 1 -> typeParamNames[1] - pIndex > 0 -> typeParamNames[0] - typeParamNames.isNotEmpty() && pIndex < 0 -> typeParamNames[0] - else -> "T" - } - return tParam to pParam - } - - /** - * Builds the type parameter string for function signatures. - * - * @param finalTypeParamBounds List of type parameter bounds - * @return Type parameter string (e.g., ">") or empty string - */ - fun buildTypeParamString(finalTypeParamBounds: List): String = if (finalTypeParamBounds.isNotEmpty()) { - "<${finalTypeParamBounds.joinToString(", ")}>" - } else { - "" - } - - /** - * Builds the return type string for function signatures. - * - * @param className The name of the class - * @param classTypeParamNames Type parameter names from the class declaration - * @return Return type string (e.g., "MyClass" or "MyClass") - */ - fun buildReturnType(className: String, classTypeParamNames: List): String = - if (classTypeParamNames.isNotEmpty()) { - "$className<${classTypeParamNames.joinToString(", ")}>" - } else { - className - } - - /** - * Collects type parameters needed for a type reference. - * - * @param typeRef The type reference to analyze - * @param existingTypeParamNames List of existing type parameter names - * @return Set of needed type parameter names - */ - fun collectNeededTypeParams(typeRef: KSTypeReference, existingTypeParamNames: List): Set { - val needed = mutableSetOf() - val resolved = typeRef.resolve() - val arguments = resolved.arguments - arguments.forEach { arg -> - processTypeArgForCollection(arg, existingTypeParamNames, needed) - } - return needed - } - - private fun processTypeArgForCollection( - arg: KSTypeArgument, - existingTypeParamNames: List, - needed: MutableSet, - ) { - when { - arg.type == null || arg.variance == Variance.STAR -> { - if (existingTypeParamNames.isEmpty()) { - needed.add("T") - } - } - else -> { - processConcreteTypeArgForCollection(arg, existingTypeParamNames, needed) - } - } - } - - private fun processConcreteTypeArgForCollection( - arg: KSTypeArgument, - existingTypeParamNames: List, - needed: MutableSet, - ) { - val argType = arg.type ?: return - val argDecl = argType.resolve().declaration - if (argDecl is KSTypeParameter) { - val paramName = argDecl.name.asString() - if (!existingTypeParamNames.contains(paramName)) { - needed.add(paramName) - } - } else { - val extracted = TypeExtractor.extractTypeString(argType, existingTypeParamNames) - if ((extracted.contains("*") || !existingTypeParamNames.any { it in extracted }) && - existingTypeParamNames.isEmpty() - ) { - needed.add("T") - } - } - } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt deleted file mode 100644 index 7eab602ac3..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/ConstructorInfo.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor.data - -import com.google.devtools.ksp.symbol.KSValueParameter - -/** - * Describes the constructor parameters before and after injection filtering. - * - * @property allParameters All parameters declared on the constructor. - * @property remainingParams Parameters the caller still needs to provide. - * @property paramsToSkip Indexes of injected parameters inside the constructor. - * @property paramNames Names assigned to the remaining parameters. - * @property paramTypes Types of the remaining parameters. - */ -internal data class ConstructorInfo( - val allParameters: List, - val remainingParams: List, - val paramsToSkip: Set, - val paramNames: List, - val paramTypes: List, -) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt deleted file mode 100644 index fad58a731e..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/GenerationContext.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor.data - -import com.google.devtools.ksp.symbol.KSClassDeclaration - -/** - * Aggregates everything needed to emit a DSL helper for a specific class. - * - * @property classDecl The declaration being processed. - * @property className Simple name of the target class. - * @property functionName Generated helper function name. - * @property typeParams Type parameter metadata for the helper. - * @property constructorInfo Constructor metadata derived from the declaration. - * @property injectionContext Information about which parameters need injection. - * @property injectedParams List of injected parameter (name,type) pairs. - * @property defaultValues Default values inferred for remaining params. - * @property needsMapEnvironment Whether a `MapEnvironment` import is required. - */ -internal data class GenerationContext( - val classDecl: KSClassDeclaration, - val className: String, - val functionName: String, - val typeParams: TypeParameterInfo, - val constructorInfo: ConstructorInfo, - val injectionContext: InjectionContext, - val injectedParams: List>, - val defaultValues: List, - val needsMapEnvironment: Boolean, -) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt deleted file mode 100644 index d475376669..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionContext.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor.data - -import it.unibo.alchemist.boundary.dsl.processor.ContextType - -/** - * Represents the injected values and annotation-driven flags available during generation. - * - * @property indices Mapping of injection types to constructor indexes. - * @property paramNames Local names allocated to injected context parameters. - * @property paramTypes Types assigned to injected context parameters. - * @property contextType Chosen context enum describing the current execution environment. - * @property hasContextParams Whether the helper defines context receivers. - * @property contextParamName Name of the context parameter used by accessors. - */ -internal data class InjectionContext( - val indices: Map, - val paramNames: Map, - val paramTypes: Map, - val contextType: ContextType, - val hasContextParams: Boolean = false, - val contextParamName: String = "ctx", -) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt deleted file mode 100644 index 9ed161ec7d..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectionType.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor.data - -/** - * Types of parameters that can be injected from context. - */ -internal enum class InjectionType { - /** Environment parameter injection. */ - ENVIRONMENT, - - /** Random generator parameter injection. */ - GENERATOR, - - /** Incarnation parameter injection. */ - INCARNATION, - - /** Node parameter injection. */ - NODE, - - /** Reaction parameter injection. */ - REACTION, - - /** Time distribution parameter injection. */ - TIMEDISTRIBUTION, - - /** Position-based filter parameter injection. */ - FILTER, -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt deleted file mode 100644 index ea1224d3a0..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/TypeParameterInfo.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor.data - -/** - * Captures the type parameter names and bounds needed inside the generated helper. - * - * @property names Generated type parameter identifiers. - * @property bounds Bounds for each generated type parameter. - * @property classTypeParamNames Original class-level type parameter names. - * @property classTypeParamBounds Original class-level type parameter bounds. - */ -internal data class TypeParameterInfo( - val names: List, - val bounds: List, - val classTypeParamNames: List = names, - val classTypeParamBounds: List = bounds, -) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclarationExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclarationExtensions.kt deleted file mode 100644 index e6914aecd2..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSClassDeclarationExtensions.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ -import com.google.devtools.ksp.isPublic -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration - -/** - * Finds a public constructor for the given class declaration. - * Prefers the primary constructor, otherwise returns the constructor - * with the most parameters. - * - * @return The found constructor, or null if no suitable constructor exists - */ -internal fun KSClassDeclaration.findConstructor(): KSFunctionDeclaration? = primaryConstructor?.takeIf { it.isPublic() } - ?: getAllFunctions() - .filter { it.isPublic() && it.simpleName.asString() in listOf("", simpleName.asString()) } - .maxByOrNull { it.parameters.size } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt deleted file mode 100644 index 467e7e6722..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor.extensions - -import com.google.devtools.ksp.symbol.KSTypeArgument -import com.google.devtools.ksp.symbol.Variance -import it.unibo.alchemist.boundary.dsl.processor.TypeExtractor -import it.unibo.alchemist.boundary.dsl.processor.replaceClassTypeParamReferences - -internal fun KSTypeArgument.format(typeParameterNames: List): String = when { - type == null -> "*" - variance == Variance.STAR -> "*" - variance == Variance.CONTRAVARIANT -> transformWithVariance(typeParameterNames, "in") - variance == Variance.COVARIANT -> transformWithVariance(typeParameterNames, "out") - else -> transformWithVariance(typeParameterNames) -} - -private fun KSTypeArgument.transformWithVariance(typeParameterNames: List, variance: String? = null): String = - type?.let { - val typeStr = TypeExtractor.extractTypeString(it, emptyList()) - sequenceOf(variance, replaceClassTypeParamReferences(typeStr, typeParameterNames)) - .filterNotNull() - .joinToString(" ") - } ?: "*" diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt index 80763b22ed..e7cc1e85c7 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt @@ -13,11 +13,5 @@ import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.symbol.KSType import it.unibo.alchemist.boundary.dsl.processor.DslBuilderProcessor -internal fun KSType.toStringWithGenerics(typeParamNames: List): String = "${declaration.typeName}${ - arguments.takeIf { it.isNotEmpty() } - ?.joinToString(prefix = "<", separator = ", ", postfix = ">") { it.format(typeParamNames) } - .orEmpty() -}${"?".takeIf { isMarkedNullable }.orEmpty()}" - context(resolver: Resolver) internal fun KSType.isInjectable() = DslBuilderProcessor.injectableTypes().any { it.isAssignableFrom(this) } From 20a9611ccc140d5c4844562950b1aef191a97d11 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Tue, 23 Dec 2025 17:18:50 +0100 Subject: [PATCH 110/196] feat: enhance simulation context to include RandomGenerator in DSL functions --- .../main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt | 8 ++++++-- .../alchemist/boundary/dsl/model/SimulationContext.kt | 2 +- .../alchemist/boundary/dsl/model/SimulationContextImpl.kt | 2 +- .../kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt | 1 + 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index f2065a20e2..2ded8dfc7e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -23,6 +23,7 @@ import it.unibo.alchemist.model.SupportedIncarnations import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.positions.Euclidean2DPosition import kotlin.jvm.optionals.getOrElse +import org.apache.commons.math3.random.RandomGenerator /** * Marker annotation for Alchemist DSL elements. @@ -95,14 +96,17 @@ object Dsl { */ fun simulation( incarnation: Incarnation, - block: context(Environment) SimulationContext.() -> Unit, + block: context( + RandomGenerator, + Environment + ) SimulationContext.() -> Unit, ): Loader { @Suppress("UNCHECKED_CAST") val defaultEnv = { Continuous2DEnvironment(incarnation) } val ctx = SimulationContextImpl(incarnation) @Suppress("UNCHECKED_CAST") ctx.apply { - context(ctx.environment) { + context(ctx.simulationGenerator, ctx.environment) { block() } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index cc190aee43..74c486dedf 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -127,7 +127,7 @@ interface SimulationContext> { * * @see [DeploymentsContextImpl] to configure deployments */ - context(environment: Environment) + context(randomGenerator: RandomGenerator, environment: Environment) fun deployments(block: DeploymentsContext.() -> Unit) /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt index f8c5c66a75..82b91a5823 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -112,7 +112,7 @@ class SimulationContextImpl>( return batchContext } - context(environment: Environment) + context(randomGenerator: RandomGenerator, environment: Environment) override fun deployments(block: DeploymentsContext.() -> Unit) { logger.debug("adding deployments block inside {}", this) buildSteps.add { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index e27d1ac1cf..cdb7eea5c9 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -28,6 +28,7 @@ import it.unibo.alchemist.model.actions.BrownianMove import it.unibo.alchemist.model.deployments.Circle import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.deployments.grid import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.layers.StepLayer From b26210589c4e43e60b2bce5a508e015238615ffc Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 00:09:33 +0100 Subject: [PATCH 111/196] feat: enhance DSL functions with context support for RandomGenerator and TimeDistribution --- .../dsl/processor/DslBuilderProcessor.kt | 70 +++++++++++-------- .../dsl/processor/InjectableConstructor.kt | 19 +++++ .../processor/data/InjectableConstructor.kt | 35 ---------- .../KSFunctionDeclarationExtensions.kt | 25 ++++++- .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 11 ++- .../dsl/model/GlobalProgramsContext.kt | 3 + .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 1 + .../alchemist/test/GlobalTestReaction.kt | 6 +- 8 files changed, 101 insertions(+), 69 deletions(-) create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/InjectableConstructor.kt delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectableConstructor.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 5350ed6964..b3632e030b 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.getClassDeclarationByName @@ -12,8 +21,8 @@ import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.validate +import injectableConstructors import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL -import it.unibo.alchemist.boundary.dsl.processor.data.InjectableConstructor import it.unibo.alchemist.boundary.dsl.processor.extensions.asString import it.unibo.alchemist.boundary.dsl.processor.extensions.nameOrTypeName import it.unibo.alchemist.boundary.dsl.processor.extensions.typeName @@ -70,14 +79,14 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val fileName = "${classDeclaration.simpleName.asString()}Factory.kt", ) val writer = PrintWriter(file, true, StandardCharsets.UTF_8) - writer.println("// This file is generated by Alchemist DSL Processor. Do not edit manually.") + writer.println("// This file is generated by the Alchemist DSL Processor. Do not edit manually.") writer.println() writer.println("package ${classDeclaration.packageName.asString()}") writer.println() val functionName = classDeclaration.simpleName.asString().replaceFirstChar { it.lowercaseChar() } val injectableConstructors = classDeclaration.getConstructors() .filter { it.isPublic() } - .mapNotNull { InjectableConstructor(it) } + .flatMap { it.injectableConstructors() } .toList() if (injectableConstructors.isEmpty()) { logger.warn( @@ -92,29 +101,12 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val writer.println(context) val typeParameters = constructor.typeParameters.takeIf { it.isNotEmpty() } ?.joinToString(prefix = "<", postfix = "> ") { typeArgument -> - buildString { - if (typeArgument.isReified) { - append("reified ") - } - append(typeArgument.name.asString()) - } + typeArgument.name.asString() } .orEmpty() val parameters = preservedParams.joinToString(separator = NEWLINE_INDENT) { parameter -> - buildString { - if (parameter.isCrossInline) { - append("crossinline ") - } - if (parameter.isNoInline) { - append("noinline ") - } - if (parameter.isVararg) { - append("vararg ") - } - append( - "${parameter.name?.asString()}: ${parameter.type.asString()}", - ) - } + val vararg = if (parameter.isVararg) "vararg " else "" + "$vararg${parameter.name?.asString()}: ${parameter.type.asString()}" } val whereClause = constructor.typeParameters .flatMap { typeParam -> @@ -125,14 +117,33 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val .takeIf { it.isNotEmpty() } ?.joinToString(separator = NEWLINE_INDENT, prefix = "where\n ", postfix = "\n") .orEmpty() - val arguments = constructor.parameters.joinToString(NEWLINE_INDENT) { - buildString { - if (it.isVararg) { - append("*") + val useAllArguments = preservedParams.size + injectableParams.size == constructor.parameters.size + val arguments = constructor.parameters.asSequence() + .run { + when { + useAllArguments -> this + else -> { + val argumentsToUse = (preservedParams + injectableParams).toSet() + filter { it in argumentsToUse } + } + } + } + .joinToString(NEWLINE_INDENT) { + /* + * If it is a Java constructor, all arguments will be used. + * Since the same is true if there are no default parameters in Kotlin, + * it is safe to call positionally if `useAllArguments` is true. + * If it is a Kotlin constructor with default parameters, named arguments must be used to + * support cases in which there are mandatory parameters after the optional ones. + */ + val name = it.name + when { + useAllArguments || name == null -> { + "${if (it.isVararg) "*" else ""}${it.nameOrTypeName()}" + } + else -> "${name.asString()} = ${it.nameOrTypeName()}" } - append(it.nameOrTypeName()) } - } writer.println( """ |fun $typeParameters$functionName( @@ -140,6 +151,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val |) $whereClause= ${classDeclaration.typeName}( | $arguments |) + | """.trimMargin(), ) } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/InjectableConstructor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/InjectableConstructor.kt new file mode 100644 index 0000000000..6924d51212 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/InjectableConstructor.kt @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor + +import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import com.google.devtools.ksp.symbol.KSValueParameter + +internal data class InjectableConstructor( + val constructor: KSFunctionDeclaration, + val injectableParameters: List, + val preservedParameters: List, +) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectableConstructor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectableConstructor.kt deleted file mode 100644 index 935bcc95bf..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/data/InjectableConstructor.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor.data - -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import com.google.devtools.ksp.symbol.KSValueParameter -import it.unibo.alchemist.boundary.dsl.processor.extensions.isInjectable - -internal data class InjectableConstructor( - val constructor: KSFunctionDeclaration, - val injectableParameters: List, - val preservedParameters: List, -) { - companion object { - context(resolver: Resolver) - operator fun invoke(constructor: KSFunctionDeclaration): InjectableConstructor? { - val (injectable, preserved) = constructor.parameters.partition { it.type.resolve().isInjectable() } - return when { - injectable.isNotEmpty() && injectable.toSet().size == injectable.size && injectable.none { - it.isVararg - } -> - InjectableConstructor(constructor, injectable, preserved) - else -> null - } - } - } -} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt index e2e5c01b73..88351f9569 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt @@ -6,9 +6,11 @@ * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ +import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.google.devtools.ksp.symbol.KSType -import com.google.devtools.ksp.symbol.KSValueParameter +import it.unibo.alchemist.boundary.dsl.processor.InjectableConstructor +import it.unibo.alchemist.boundary.dsl.processor.extensions.isInjectable /** * Finds a public constructor for the given class declaration. @@ -18,3 +20,24 @@ import com.google.devtools.ksp.symbol.KSValueParameter * @return The found constructor, or null if no suitable constructor exists */ internal val KSFunctionDeclaration.parameterTypes: List get() = parameters.map { it.type.resolve() } + +context(resolver: Resolver) +internal fun KSFunctionDeclaration.injectableConstructors(): List { + val (injectable, preserved) = parameters.partition { it.type.resolve().isInjectable() } + return when { + injectable.isNotEmpty() && + injectable.toSet().size == injectable.size && + injectable.none { it.isVararg } -> { + val defaultParameters = parameters.filter { it.hasDefault } + (0..defaultParameters.size).map { toDrop -> + val defaultParametersToDrop = defaultParameters.drop(toDrop).toSet() + InjectableConstructor( + this, + injectable - defaultParametersToDrop, + preserved - defaultParametersToDrop, + ) + } + } + else -> emptyList() + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index 2ded8dfc7e..734e533b2e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -79,11 +79,18 @@ object Dsl { fun > simulation( incarnation: Incarnation, environment: () -> Environment, - block: SimulationContext.() -> Unit, + block: context( + RandomGenerator, + Environment + ) SimulationContext.() -> Unit, ): Loader { val ctx = SimulationContextImpl(incarnation) @Suppress("UNCHECKED_CAST") - ctx.apply(block) + ctx.apply { + context(ctx.simulationGenerator, ctx.environment) { + block() + } + } return createLoader(ctx, environment) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt index 472752a80b..97475c2181 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt @@ -11,6 +11,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.model.GlobalReaction import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.TimeDistribution /** * Context for configuring global reactions in a simulation. @@ -27,6 +28,7 @@ interface GlobalProgramsContext> { * * @param this The global reaction to add. */ + context(timeDistribution: TimeDistribution) operator fun GlobalReaction.unaryPlus() } @@ -38,6 +40,7 @@ interface GlobalProgramsContext> { */ class GlobalProgramsContextImpl>(override val ctx: SimulationContext) : GlobalProgramsContext { + context(timeDistribution: TimeDistribution) override fun GlobalReaction.unaryPlus() { ctx.environment.addGlobalReaction(this) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index cdb7eea5c9..a0c5e7e9a2 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -18,6 +18,7 @@ import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.SAPERE import it.unibo.alchemist.boundary.exporters.CSVExporter import it.unibo.alchemist.boundary.exportfilters.CommonFilters import it.unibo.alchemist.boundary.extractors.Time +import it.unibo.alchemist.boundary.extractors.moleculeReader import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution diff --git a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt index daca33f6a1..311ac60905 100644 --- a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt +++ b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -9,6 +9,7 @@ package it.unibo.alchemist.test +import it.unibo.alchemist.boundary.dsl.AlchemistDsl import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Condition @@ -20,7 +21,8 @@ import it.unibo.alchemist.model.TimeDistribution import org.danilopianini.util.ListSet import org.danilopianini.util.ListSets -class GlobalTestReaction(override val timeDistribution: TimeDistribution, val environment: Environment) : +@AlchemistDsl +class GlobalTestReaction(val environment: Environment, override val timeDistribution: TimeDistribution) : GlobalReaction { override fun compareTo(other: Actionable): Int = tau.compareTo(other.tau) From 54f80ce98a1fa1b05b75e641689af954bc300b12 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 00:20:19 +0100 Subject: [PATCH 112/196] fix: update copyright year and improve GlobalTestReaction usage in tests --- .../processor/extensions/KSTypeReferenceExtensions.kt | 3 +++ .../it/unibo/alchemist/core/TestSimulationControl.kt | 4 ++-- .../alchemist/core/test/GoToTimeRegressionTest.kt | 11 ++++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt index 6fb40f2eb9..4ee9e68743 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt @@ -25,4 +25,7 @@ internal fun KSTypeReference.asString(): String = buildString { }, ) } + if (type.isMarkedNullable) { + append("?") + } } diff --git a/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/TestSimulationControl.kt b/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/TestSimulationControl.kt index a4cbe79af7..c31f92abd4 100644 --- a/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/TestSimulationControl.kt +++ b/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/TestSimulationControl.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -68,7 +68,7 @@ class TestSimulationControl : fun Environment.tickRate(delta: Double) { this.simulation.schedule { - this.addGlobalReaction(GlobalTestReaction(DiracComb(Time.ZERO, delta), this)) + this.addGlobalReaction(GlobalTestReaction(this, DiracComb(Time.ZERO, delta))) } } } diff --git a/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/test/GoToTimeRegressionTest.kt b/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/test/GoToTimeRegressionTest.kt index 07834115f6..4742563fec 100644 --- a/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/test/GoToTimeRegressionTest.kt +++ b/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/test/GoToTimeRegressionTest.kt @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.core.test import it.unibo.alchemist.model.Environment @@ -24,7 +33,7 @@ object GoToTimeRegressionTest { private fun Environment.tickRate(delta: Double) { this.simulation.schedule { - this.addGlobalReaction(GlobalTestReaction(DiracComb(Time.ZERO, delta), this)) + this.addGlobalReaction(GlobalTestReaction(this, DiracComb(Time.ZERO, delta))) } } From 3b5c58d5928310aa954aaa118b5de752cf5c6924 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 01:00:59 +0100 Subject: [PATCH 113/196] fix: update copyright year to 2025 in Circle.java --- .../main/java/it/unibo/alchemist/model/deployments/Circle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java index 195873e696..287dbb07aa 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the From 971256d724435c711ac6aff337d8ba1f1766b673 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 01:02:07 +0100 Subject: [PATCH 114/196] fix: update copyright year to 2025 in CircularArc.kt --- .../it/unibo/alchemist/model/deployments/CircularArc.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt index 77a7fcb998..a88a20ec4c 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.model.deployments import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL From 7e022944deba238697a014f63628bdbfcde6289e Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 01:04:49 +0100 Subject: [PATCH 115/196] fix: update copyright year to 2025 in multiple files --- .../alchemist/model/timedistributions/ExponentialTime.java | 2 +- .../model/deployments/GeometricGradientRectangle.java | 2 +- .../main/java/it/unibo/alchemist/model/deployments/Point.java | 2 +- .../java/it/unibo/alchemist/model/deployments/Rectangle.java | 2 +- .../it/unibo/alchemist/boundary/extractors/MoleculeReader.kt | 2 +- .../alchemist/model/deployments/CloseToAlreadyDeployed.kt | 2 +- .../unibo/alchemist/model/deployments/GraphStreamDeployment.kt | 2 +- .../main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt | 2 +- .../kotlin/it/unibo/alchemist/model/deployments/Polygon.kt | 2 +- .../it/unibo/alchemist/model/deployments/SpecificPositions.kt | 3 ++- .../src/test/java/it/unibo/alchemist/model/nodes/TestNode.java | 2 +- 11 files changed, 12 insertions(+), 11 deletions(-) diff --git a/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java b/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java index adc9134d7c..21edac020c 100644 --- a/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java +++ b/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java index c403d76996..2de9c59b60 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java index 16c1cfdcee..299a4adb02 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java index f12ae1b5e4..fa03f957e6 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt index a9a5c757aa..776077891b 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt index 8cd745e3f5..f487be5213 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt index d8fa638b96..ac2e5bc907 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt index 11b5cb926a..f30b0bfe92 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt index 58e59c8435..034ea1493d 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt index c87a17f6ca..984b1dbfc1 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt @@ -1,5 +1,6 @@ /* - * Copyright (C) 2010-2019, Danilo Pianini and contributors listed in the main project's alchemist/build.gradle file. + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the * GNU General Public License, with a linking exception, diff --git a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java index 8c3d09989e..bc5a4399da 100644 --- a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java +++ b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the From aea5ca47dbb82d2ce7b9d80017331bd5e9ecd755 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 01:11:31 +0100 Subject: [PATCH 116/196] fix: remove scope from AlchemistKotlinDSL annotation in TestNode.java --- .../src/test/java/it/unibo/alchemist/model/nodes/TestNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java index bc5a4399da..2d506fb354 100644 --- a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java +++ b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java @@ -17,7 +17,7 @@ /** * Generic node for testing purposes. */ -@AlchemistKotlinDSL(scope = "DEPLOYMENT_CONTEXT") +@AlchemistKotlinDSL public final class TestNode extends GenericNode { @Serial From 5a350a8ba1dfb30cf11a525a1aa3886c25fc56c7 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 01:11:42 +0100 Subject: [PATCH 117/196] fix: remove scope from AlchemistKotlinDSL annotation in TestNode.java --- .../alchemist/boundary/properties/TestNodeProperty.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt index 1dd70d58c4..baf75c9e31 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt @@ -20,17 +20,17 @@ import org.apache.commons.math3.random.RandomGenerator @AlchemistKotlinDSL class TestNodeProperty>( - node: Node, - val environment: Environment, val incarnation: Incarnation, val rng: RandomGenerator, + val environment: Environment, + node: Node, val s: String, ) : AbstractNodeProperty(node) { override fun cloneOnNewNode(node: Node): NodeProperty = TestNodeProperty( - node, - environment, incarnation, rng, + environment, + node, s, ) From 9ddc7827536c7aad916e46016f4044666bcedfb9 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 01:13:01 +0100 Subject: [PATCH 118/196] fix: update context parameters in simulation function and change annotation to AlchemistKotlinDSL --- .../src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt | 3 ++- .../main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index 734e533b2e..cb1e1c1229 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -104,6 +104,7 @@ object Dsl { fun simulation( incarnation: Incarnation, block: context( + Incarnation, RandomGenerator, Environment ) SimulationContext.() -> Unit, @@ -113,7 +114,7 @@ object Dsl { val ctx = SimulationContextImpl(incarnation) @Suppress("UNCHECKED_CAST") ctx.apply { - context(ctx.simulationGenerator, ctx.environment) { + context(incarnation, ctx.simulationGenerator, ctx.environment) { block() } } diff --git a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt index 311ac60905..1678aac2f8 100644 --- a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt +++ b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt @@ -9,7 +9,7 @@ package it.unibo.alchemist.test -import it.unibo.alchemist.boundary.dsl.AlchemistDsl +import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Condition @@ -21,7 +21,7 @@ import it.unibo.alchemist.model.TimeDistribution import org.danilopianini.util.ListSet import org.danilopianini.util.ListSets -@AlchemistDsl +@AlchemistKotlinDSL class GlobalTestReaction(val environment: Environment, override val timeDistribution: TimeDistribution) : GlobalReaction { override fun compareTo(other: Actionable): Int = tau.compareTo(other.tau) From db323d162ebdf337679b90bbe0f8c80b7e96e99e Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 01:13:16 +0100 Subject: [PATCH 119/196] fix: suppress Detekt false positive for undocumented public function in GlobalProgramsContext --- .../unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt index 97475c2181..353d3362f6 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt @@ -19,6 +19,7 @@ import it.unibo.alchemist.model.TimeDistribution * @param T The type of molecule concentration. * @param P The type of position. */ +@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters interface GlobalProgramsContext> { /** The parent simulation context. */ val ctx: SimulationContext From 055cce944eb4fc93b616c46e15072914263e9bbe Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 01:16:11 +0100 Subject: [PATCH 120/196] fix: update copyright year to 2025 in build.gradle.kts --- alchemist-test/build.gradle.kts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/alchemist-test/build.gradle.kts b/alchemist-test/build.gradle.kts index ee91298347..40893930b4 100644 --- a/alchemist-test/build.gradle.kts +++ b/alchemist-test/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -9,15 +9,6 @@ import Libs.alchemist -/* - * Copyright (C) 2010-2020, Danilo Pianini and contributors - * listed in the main project's alchemist/build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - plugins { id("kotlin-jvm-convention") alias(libs.plugins.ksp) From d4ac5bf3ed9e63695a3abb737cd15fb56165b5fb Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 01:16:41 +0100 Subject: [PATCH 121/196] build: use the correct ksp dependency --- alchemist-test/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-test/build.gradle.kts b/alchemist-test/build.gradle.kts index 40893930b4..8cb7928331 100644 --- a/alchemist-test/build.gradle.kts +++ b/alchemist-test/build.gradle.kts @@ -15,6 +15,7 @@ plugins { } dependencies { + ksp(alchemist("dsl-processor")) api(alchemist("api")) api(alchemist("engine")) api(alchemist("loading")) @@ -24,7 +25,6 @@ dependencies { implementation(alchemist("physics")) runtimeOnly(libs.bundles.testing.runtimeOnly) implementation(libs.ksp) - ksp(project(":alchemist-dsl-processor")) } publishing.publications { From 1d99cc8e01225c0be8cad9a8ad8a173bc7fc7e90 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 24 Dec 2025 01:17:25 +0100 Subject: [PATCH 122/196] fix: update globalTestReaction call to use generic type and correct Rectangle instantiation --- .../kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index a0c5e7e9a2..c0058530c2 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -19,6 +19,7 @@ import it.unibo.alchemist.boundary.exporters.CSVExporter import it.unibo.alchemist.boundary.exportfilters.CommonFilters import it.unibo.alchemist.boundary.extractors.Time import it.unibo.alchemist.boundary.extractors.moleculeReader +import it.unibo.alchemist.boundary.properties.testNodeProperty import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution @@ -29,14 +30,17 @@ import it.unibo.alchemist.model.actions.BrownianMove import it.unibo.alchemist.model.deployments.Circle import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.deployments.circle import it.unibo.alchemist.model.deployments.grid import it.unibo.alchemist.model.deployments.point +import it.unibo.alchemist.model.deployments.polygon import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.layers.StepLayer import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.maps.actions.ReproduceGPSTrace import it.unibo.alchemist.model.maps.deployments.FromGPSTrace import it.unibo.alchemist.model.maps.environments.OSMEnvironment +import it.unibo.alchemist.model.nodes.testNode import it.unibo.alchemist.model.positionfilters.Rectangle import it.unibo.alchemist.model.positions.Euclidean2DPosition import it.unibo.alchemist.model.reactions.Event @@ -46,6 +50,7 @@ import it.unibo.alchemist.model.timedistributions.DiracComb import it.unibo.alchemist.model.timedistributions.ExponentialTime import it.unibo.alchemist.model.timedistributions.WeibullTime import it.unibo.alchemist.model.times.DoubleTime +import it.unibo.alchemist.test.globalTestReaction import org.apache.commons.math3.random.MersenneTwister object DslLoaderFunctions { @@ -315,7 +320,7 @@ object DslLoaderFunctions { val incarnation = PROTELIS.incarnation() return simulation(incarnation) { programs { - +globalTestReaction(DiracComb(1.0)) + +globalTestReaction(DiracComb(1.0)) } } } @@ -445,7 +450,7 @@ object DslLoaderFunctions { ), ) { properties { - val filter = RectangleFilter(-3.0, -3.0, 2.0, 2.0) + val filter = Rectangle(-3.0, -3.0, 2.0, 2.0) // same val filter2 = Rectangle(3.0, 3.0, 2.0, 2.0) inside(filter) { From 124bf87ad1b553671bbe6f60d142f3fb3e12cc3a Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 26 Dec 2025 22:28:57 +0100 Subject: [PATCH 123/196] refactor: remove AlchemistKotlinDSL annotation from multiple classes --- .../boundary/dsl/AlchemistKotlinDSL.kt | 19 --- .../dsl/processor/DslBuilderProcessor.kt | 143 ++++++++---------- .../processor/DslBuilderProcessorProvider.kt | 11 +- .../KSFunctionDeclarationExtensions.kt | 41 +++-- .../processor/extensions/ListExtensions.kt | 23 +++ .../timedistributions/ExponentialTime.java | 2 - .../alchemist/model/deployments/Circle.java | 2 - .../GeometricGradientRectangle.java | 2 - .../alchemist/model/deployments/Point.java | 2 - .../model/deployments/Rectangle.java | 2 - .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 2 +- .../dsl/model/GlobalProgramsContext.kt | 3 - .../boundary/dsl/model/SimulationContext.kt | 8 +- .../dsl/model/SimulationContextImpl.kt | 2 +- .../boundary/extractors/MoleculeReader.kt | 8 +- .../model/deployments/CircularArc.kt | 2 - .../deployments/CloseToAlreadyDeployed.kt | 2 - .../deployments/GraphStreamDeployment.kt | 2 - .../unibo/alchemist/model/deployments/Grid.kt | 2 - .../alchemist/model/deployments/Polygon.kt | 2 - .../model/deployments/SpecificPositions.kt | 2 - .../unibo/alchemist/model/nodes/TestNode.java | 2 - .../boundary/properties/TestNodeProperty.kt | 2 - .../alchemist/test/GlobalTestReaction.kt | 2 - 24 files changed, 131 insertions(+), 157 deletions(-) delete mode 100644 alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/ListExtensions.kt diff --git a/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt b/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt deleted file mode 100644 index 7f66c8492a..0000000000 --- a/alchemist-api/src/main/kotlin/it/unibo/alchemist/boundary/dsl/AlchemistKotlinDSL.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl - -/** - * Annotation used to mark classes that should have DSL builder functions generated. - * When applied to a class, the DSL processor will generate a builder function - * that can be used in Alchemist DSL scripts to create instances of the annotated class. - */ -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.SOURCE) -annotation class AlchemistKotlinDSL diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index b3632e030b..9dd01d5678 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -11,19 +11,18 @@ package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.getClassDeclarationByName import com.google.devtools.ksp.getConstructors +import com.google.devtools.ksp.isAbstract import com.google.devtools.ksp.isPublic import com.google.devtools.ksp.processing.CodeGenerator import com.google.devtools.ksp.processing.Dependencies -import com.google.devtools.ksp.processing.KSPLogger import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.processing.SymbolProcessor import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSType -import com.google.devtools.ksp.validate -import injectableConstructors -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL +import com.google.devtools.ksp.symbol.KSTypeParameter import it.unibo.alchemist.boundary.dsl.processor.extensions.asString +import it.unibo.alchemist.boundary.dsl.processor.extensions.injectableConstructors import it.unibo.alchemist.boundary.dsl.processor.extensions.nameOrTypeName import it.unibo.alchemist.boundary.dsl.processor.extensions.typeName import it.unibo.alchemist.core.Simulation @@ -38,72 +37,63 @@ import java.nio.charset.StandardCharsets import org.apache.commons.math3.random.RandomGenerator /** Symbol processor that emits DSL helpers for `@AlchemistKotlinDSL` classes. */ -class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) : SymbolProcessor { +class DslBuilderProcessor(private val codeGenerator: CodeGenerator) : SymbolProcessor { - /** - * Processes every `@AlchemistKotlinDSL` symbol, - * generating helpers and returning unresolved ones. - */ override fun process(resolver: Resolver): List { context(resolver) { - logger.dslInfo("Starting processing") - val annotationName = AlchemistKotlinDSL::class.qualifiedName - check(!annotationName.isNullOrBlank()) { - "The Alchemist Kotlin DSL annotation name is invalid or missing: '$annotationName'" - } - logger.dslInfo("Alchemist DSL annotation: $annotationName") - return resolver.getSymbolsWithAnnotation(annotationName) - .fold(emptyList()) { invalidElements, symbol -> - when { - !symbol.validate() -> invalidElements + symbol - else -> { - if (symbol is KSClassDeclaration) { - processClass(symbol) - } - invalidElements - } + resolver.getNewFiles() + .flatMap { it.declarations } + .filterIsInstance() + .filter { it.isPublic() && !it.isAbstract() } + .forEach { classDeclaration -> + val injectableConstructors = classDeclaration.getConstructors() + .flatMap { it.injectableConstructors() } + .toList() + if (injectableConstructors.isNotEmpty()) { + val file = codeGenerator.createNewFile( + dependencies = classDeclaration.containingFile + ?.let { Dependencies(false, it) } + ?: Dependencies.ALL_FILES, + packageName = classDeclaration.packageName.asString(), + fileName = "${classDeclaration.simpleName.asString()}Factory.kt", + ) + val writer = PrintWriter(file, true, StandardCharsets.UTF_8) + writer.println("// This file is generated by the Alchemist DSL Processor. Do not edit.\n") + writer.println("package ${classDeclaration.packageName.asString()}\n") + injectableConstructors.forEach { processConstructor(writer, classDeclaration, it) } } } } + return emptyList() } - context(resolver: Resolver) - private fun processClass(classDeclaration: KSClassDeclaration) { - logger.dslInfo("Processing class ${classDeclaration.simpleName.asString()}") - logger.dslInfo("Class qualified name: ${classDeclaration.qualifiedName?.asString()}") - val file = codeGenerator.createNewFile( - dependencies = classDeclaration.containingFile - ?.let { Dependencies(false, it) } - ?: Dependencies.ALL_FILES, - packageName = classDeclaration.packageName.asString(), - fileName = "${classDeclaration.simpleName.asString()}Factory.kt", - ) - val writer = PrintWriter(file, true, StandardCharsets.UTF_8) - writer.println("// This file is generated by the Alchemist DSL Processor. Do not edit manually.") - writer.println() - writer.println("package ${classDeclaration.packageName.asString()}") - writer.println() - val functionName = classDeclaration.simpleName.asString().replaceFirstChar { it.lowercaseChar() } - val injectableConstructors = classDeclaration.getConstructors() - .filter { it.isPublic() } - .flatMap { it.injectableConstructors() } - .toList() - if (injectableConstructors.isEmpty()) { - logger.warn( - "No injectable constructors, ${AlchemistKotlinDSL::class.qualifiedName} will have no effect.", - classDeclaration, - ) - } - injectableConstructors.forEach { (constructor, injectableParams, preservedParams) -> + internal companion object { + + const val NEWLINE_INDENT = ",\n| " + + context(resolver: Resolver) + fun injectableTypes(): Set = sequenceOf( + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName(), + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), + ).map { checkNotNull(it).asStarProjectedType() }.toSet() + + private fun processConstructor( + writer: PrintWriter, + classDeclaration: KSClassDeclaration, + injectableConstructor: InjectableConstructor, + ) { + val (constructor, injectableParams, preservedParams) = injectableConstructor val context = injectableParams.joinToString(prefix = "context(", postfix = ")") { param -> "${param.nameOrTypeName()}: ${param.type.asString()}" } writer.println(context) - val typeParameters = constructor.typeParameters.takeIf { it.isNotEmpty() } - ?.joinToString(prefix = "<", postfix = "> ") { typeArgument -> - typeArgument.name.asString() - } - .orEmpty() + val typeParameters = constructor.typeParameters.render() val parameters = preservedParams.joinToString(separator = NEWLINE_INDENT) { parameter -> val vararg = if (parameter.isVararg) "vararg " else "" "$vararg${parameter.name?.asString()}: ${parameter.type.asString()}" @@ -144,35 +134,24 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator, private val else -> "${name.asString()} = ${it.nameOrTypeName()}" } } + val functionName = classDeclaration.simpleName.asString().replaceFirstChar { it.lowercaseChar() } + val contextParameterNames = injectableParams.joinToString("") { param -> + param.nameOrTypeName().replaceFirstChar { it.uppercase() } + } + val argumentsString = if (parameters.isEmpty()) "()" else "(\n| $parameters\n|)" writer.println( """ - |fun $typeParameters$functionName( - | $parameters - |) $whereClause= ${classDeclaration.typeName}( - | $arguments - |) - | + |@JvmName("${functionName}WithContextual$contextParameterNames") + |fun $typeParameters$functionName$argumentsString $whereClause= ${classDeclaration.typeName}( + | $arguments + |) + | """.trimMargin(), ) } - } - internal companion object { - - const val NEWLINE_INDENT = ",\n| " - - private fun KSPLogger.dslInfo(message: String) = info("${DslBuilderProcessor::class.simpleName}: $message") - - context(resolver: Resolver) - fun injectableTypes(): Set = sequenceOf( - resolver.getClassDeclarationByName>(), - resolver.getClassDeclarationByName>(), - resolver.getClassDeclarationByName>(), - resolver.getClassDeclarationByName>(), - resolver.getClassDeclarationByName(), - resolver.getClassDeclarationByName>(), - resolver.getClassDeclarationByName>(), - resolver.getClassDeclarationByName>(), - ).map { checkNotNull(it).asStarProjectedType() }.toSet() + private fun List.render() = takeIf { it.isNotEmpty() } + ?.joinToString(prefix = "<", postfix = "> ") { typeArgument -> typeArgument.name.asString() } + .orEmpty() } } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt index ed5d044265..02180bc309 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.boundary.dsl.processor import com.google.devtools.ksp.processing.SymbolProcessor @@ -9,5 +18,5 @@ import com.google.devtools.ksp.processing.SymbolProcessorProvider */ class DslBuilderProcessorProvider : SymbolProcessorProvider { override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = - DslBuilderProcessor(environment.codeGenerator, environment.logger) + DslBuilderProcessor(environment.codeGenerator) } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt index 88351f9569..cca2598906 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt @@ -6,11 +6,14 @@ * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ + +package it.unibo.alchemist.boundary.dsl.processor.extensions + +import com.google.devtools.ksp.isPublic import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.google.devtools.ksp.symbol.KSType import it.unibo.alchemist.boundary.dsl.processor.InjectableConstructor -import it.unibo.alchemist.boundary.dsl.processor.extensions.isInjectable /** * Finds a public constructor for the given class declaration. @@ -22,22 +25,28 @@ import it.unibo.alchemist.boundary.dsl.processor.extensions.isInjectable internal val KSFunctionDeclaration.parameterTypes: List get() = parameters.map { it.type.resolve() } context(resolver: Resolver) -internal fun KSFunctionDeclaration.injectableConstructors(): List { - val (injectable, preserved) = parameters.partition { it.type.resolve().isInjectable() } - return when { - injectable.isNotEmpty() && - injectable.toSet().size == injectable.size && - injectable.none { it.isVararg } -> { - val defaultParameters = parameters.filter { it.hasDefault } - (0..defaultParameters.size).map { toDrop -> - val defaultParametersToDrop = defaultParameters.drop(toDrop).toSet() - InjectableConstructor( - this, - injectable - defaultParametersToDrop, - preserved - defaultParametersToDrop, - ) +internal fun KSFunctionDeclaration.injectableConstructors(): Sequence = when { + isPublic() -> { + val injectable = parameters.filter { !it.hasDefault && it.type.resolve().isInjectable() } + val injectabletypes = injectable.map { it.type.resolve() }.toSet() + when { + injectabletypes.size == injectable.size && injectable.none { it.isVararg } -> { + val defaultParameters = parameters.filter { it.hasDefault } + injectable.powerSetWithoutEmptySet().flatMap { toInject -> + val toInjectSet = toInject.toSet() + val valueParameters = parameters - toInjectSet + (0..defaultParameters.size).asSequence().map { toDrop -> + val defaultParametersToDrop = defaultParameters.drop(toDrop).toSet() + InjectableConstructor( + this, + toInject - defaultParametersToDrop, + valueParameters - defaultParametersToDrop, + ) + } + } } + else -> emptySequence() } - else -> emptyList() } + else -> emptySequence() } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/ListExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/ListExtensions.kt new file mode 100644 index 0000000000..d7bed55d43 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/ListExtensions.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.extensions + +internal fun List.powerSetWithoutEmptySet(): Sequence> = sequence { + val numberOfSubsets = 1 shl size // 2^n subsets + for (i in 1 until numberOfSubsets) { + val subset = mutableListOf() + for (j in 0 until size) { + if (i and (1 shl j) != 0) { + subset.add(this@powerSetWithoutEmptySet[j]) + } + } + yield(subset) + } +} diff --git a/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java b/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java index 21edac020c..67fe869f04 100644 --- a/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java +++ b/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/timedistributions/ExponentialTime.java @@ -10,7 +10,6 @@ package it.unibo.alchemist.model.timedistributions; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Node; import it.unibo.alchemist.model.Time; @@ -26,7 +25,6 @@ * * @param concentration type */ -@AlchemistKotlinDSL public class ExponentialTime extends AbstractDistribution { @Serial diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java index 287dbb07aa..e903ea03e3 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Circle.java @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.deployments; -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; import org.apache.commons.math3.random.RandomGenerator; @@ -24,7 +23,6 @@ /** * @param

{@link Position} type */ -@AlchemistKotlinDSL public final class Circle

> extends AbstractRandomDeployment

{ private final double centerX; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java index 2de9c59b60..4f7cb8eb4b 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/GeometricGradientRectangle.java @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.deployments; -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; import org.apache.commons.math3.distribution.ExponentialDistribution; @@ -23,7 +22,6 @@ * * @param

position type */ -@AlchemistKotlinDSL public final class GeometricGradientRectangle

> extends Rectangle

{ private final ExponentialDistribution exp; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java index 299a4adb02..e783ff2319 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.deployments; -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Deployment; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; @@ -22,7 +21,6 @@ * * @param

position type */ -@AlchemistKotlinDSL public final class Point

> implements Deployment

{ private final double x; diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java index fa03f957e6..413c9604cb 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Rectangle.java @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.deployments; -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Position; import org.apache.commons.math3.random.RandomGenerator; @@ -19,7 +18,6 @@ /** * @param

position type */ -@AlchemistKotlinDSL public class Rectangle

> extends AbstractRandomDeployment

{ private final double x; diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index cb1e1c1229..b18e3906d9 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -48,7 +48,7 @@ object Dsl { * @return A loader instance. */ fun > createLoader( - builder: SimulationContextImpl, + builder: SimulationContext, envBuilder: () -> Environment, ): Loader = object : DSLLoader(builder, envBuilder) { override val constants: Map = emptyMap() diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt index 353d3362f6..c979c15ebc 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt @@ -11,7 +11,6 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.model.GlobalReaction import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.TimeDistribution /** * Context for configuring global reactions in a simulation. @@ -29,7 +28,6 @@ interface GlobalProgramsContext> { * * @param this The global reaction to add. */ - context(timeDistribution: TimeDistribution) operator fun GlobalReaction.unaryPlus() } @@ -41,7 +39,6 @@ interface GlobalProgramsContext> { */ class GlobalProgramsContextImpl>(override val ctx: SimulationContext) : GlobalProgramsContext { - context(timeDistribution: TimeDistribution) override fun GlobalReaction.unaryPlus() { ctx.environment.addGlobalReaction(this) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 74c486dedf..e370afe118 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -12,7 +12,6 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.AlchemistDsl import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GlobalReaction @@ -216,4 +215,11 @@ interface SimulationContext> { * @param source A function that computes the variable value */ fun variable(source: () -> A): VariablesContext.DependentVariableProvider + + /** + * The context managing variables for batch simulations. + * + * @see [VariablesContext] + */ + val variablesContext: VariablesContext } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt index 82b91a5823..92d8162b3a 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -92,7 +92,7 @@ class SimulationContextImpl>( /** * The variables context for managing simulation variables. */ - val variablesContext = VariablesContext() + override val variablesContext = VariablesContext() /** * Build a fresh new simulation context instance, and applies diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt index 776077891b..3fbae31a28 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt @@ -10,7 +10,6 @@ package it.unibo.alchemist.boundary.extractors import it.unibo.alchemist.boundary.ExportFilter -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation @@ -31,11 +30,10 @@ import kotlin.math.min * @param filter * the [FilteringPolicy] to use * @param aggregatorNames - * the names of the [UnivariateStatistic] to use for - * aggregating data. If an empty list is passed, then the values - * will be logged indipendently for each node. + * the names of the [org.apache.commons.math.stat.descriptive.UnivariateStatistic] to use for + * aggregating data. If an empty list is passed, then the values + * will be logged indipendently for each node. */ -@AlchemistKotlinDSL class MoleculeReader @JvmOverloads constructor( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt index a88a20ec4c..14598784af 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CircularArc.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position2D @@ -30,7 +29,6 @@ import org.apache.commons.math3.random.RandomGenerator * * Default values generate a uniform deployment on a circumference. */ -@AlchemistKotlinDSL data class CircularArc

> @JvmOverloads constructor( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt index f487be5213..2ee71abe18 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/CloseToAlreadyDeployed.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Position @@ -20,7 +19,6 @@ import org.apache.commons.math3.random.RandomGenerator * in the proximity of those already included in the environment. * Behaviour if there are no nodes already inserted is undefined. */ -@AlchemistKotlinDSL class CloseToAlreadyDeployed>( randomGenerator: RandomGenerator, environment: Environment, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt index ac2e5bc907..550b05be93 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/GraphStreamDeployment.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.LinkingRule @@ -20,7 +19,6 @@ import org.apache.commons.math3.random.RandomGenerator /** * A deployment based on a [GraphStream](https://github.com/graphstream) graph. */ -@AlchemistKotlinDSL class GraphStreamDeployment

( private val createLinks: Boolean, private val graphStreamSupport: GraphStreamSupport<*, P>, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt index f30b0bfe92..91d216cb76 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt @@ -8,7 +8,6 @@ */ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position @@ -46,7 +45,6 @@ import org.apache.commons.math3.random.RandomGenerator * @param yShift * how shifted should be positions along columns */ -@AlchemistKotlinDSL open class Grid @JvmOverloads constructor( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt index 034ea1493d..29f0760a7e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Polygon.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Position2D @@ -34,7 +33,6 @@ private typealias Point2D = Pair * undefined. There polygon is closed automatically (there is no need to pass the first point also as last element). * */ -@AlchemistKotlinDSL open class Polygon

>( environment: Environment<*, P>, randomGenerator: RandomGenerator, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt index 984b1dbfc1..ea5ffd81db 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/SpecificPositions.kt @@ -8,7 +8,6 @@ */ package it.unibo.alchemist.model.deployments -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position @@ -16,7 +15,6 @@ import it.unibo.alchemist.model.Position /** * Given an environment and a list of list of numbers, it creates a list of the right position type for the environment. */ -@AlchemistKotlinDSL class SpecificPositions(environment: Environment<*, *>, vararg positions: Iterable) : Deployment> { private val positions: List> = positions.map { environment.makePosition(*it.toList().toTypedArray()) } diff --git a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java index 2d506fb354..61b9b48f86 100644 --- a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java +++ b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.nodes; -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL; import it.unibo.alchemist.model.Environment; import java.io.Serial; @@ -17,7 +16,6 @@ /** * Generic node for testing purposes. */ -@AlchemistKotlinDSL public final class TestNode extends GenericNode { @Serial diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt index baf75c9e31..c32ef8799f 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.boundary.properties -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Node @@ -18,7 +17,6 @@ import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.properties.AbstractNodeProperty import org.apache.commons.math3.random.RandomGenerator -@AlchemistKotlinDSL class TestNodeProperty>( val incarnation: Incarnation, val rng: RandomGenerator, diff --git a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt index 1678aac2f8..168c472ee2 100644 --- a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt +++ b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/GlobalTestReaction.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.test -import it.unibo.alchemist.boundary.dsl.AlchemistKotlinDSL import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Condition @@ -21,7 +20,6 @@ import it.unibo.alchemist.model.TimeDistribution import org.danilopianini.util.ListSet import org.danilopianini.util.ListSets -@AlchemistKotlinDSL class GlobalTestReaction(val environment: Environment, override val timeDistribution: TimeDistribution) : GlobalReaction { override fun compareTo(other: Actionable): Int = tau.compareTo(other.tau) From 4f65913e1996198dc2477cf4c0392b975496c3c8 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 1 Jan 2026 22:20:14 +0100 Subject: [PATCH 124/196] refactor: major redesign of the DSL --- alchemist-cognitive-agents/build.gradle.kts | 4 +- .../model/cognitive/steering/TypeBased.kt | 4 +- .../alchemist/model/cognitive/TestSensory.kt | 61 +- .../dsl/processor/DslBuilderProcessor.kt | 110 +- .../dsl/processor/InjectableConstructor.kt | 19 - .../datatypes/InjectableConstructor.kt | 42 + .../dsl/processor/datatypes/TypePosition.kt | 12 + .../KSFunctionDeclarationExtensions.kt | 4 +- .../extensions/KSTypeArgumentExtensions.kt | 27 + .../processor/extensions/KSTypeExtensions.kt | 49 +- .../extensions/KSTypeReferenceExtensions.kt | 22 +- .../unibo/alchemist/core/TestConcurrency.kt | 4 +- alchemist-euclidean-geometry/build.gradle.kts | 4 +- .../obstacles/TestContinuous2DObstacle.java | 4 +- .../model/neighborhoods/TestNeighborhood.kt | 17 +- alchemist-implementationbase/build.gradle.kts | 4 +- .../alchemist/model/nodes/GenericNode.kt | 12 +- .../unibo/alchemist/util/TestDiameterUtils.kt | 4 +- .../build.gradle.kts | 8 +- .../biochemistry/BiochemistryIncarnation.java | 4 +- .../nodes/EnvironmentNodeImpl.java | 15 +- .../properties/TestDeformableCell.java | 4 +- .../build.gradle.kts | 11 + .../model/protelis/ProtelisIncarnation.kt | 4 +- alchemist-incarnation-sapere/build.gradle.kts | 5 +- .../model/sapere/SAPEREIncarnation.java | 15 +- .../sapere/actions/LsaAllNeighborsAction.java | 28 +- .../actions/LsaRandomNeighborAction.java | 14 +- .../sapere/actions/LsaStandardAction.java | 19 +- .../alchemist/model/ScafiIncarnation.scala | 5 +- alchemist-loading/build.gradle.kts | 7 +- .../unibo/alchemist/boundary/dsl/DSLLoader.kt | 10 +- .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 29 +- .../dsl/model/AvailableIncarnations.kt | 35 - .../boundary/dsl/model/ContentContext.kt | 24345 ++++++++++++++++ .../boundary/dsl/model/DeploymentContext.kt | 124 +- .../boundary/dsl/model/DeploymentsContext.kt | 93 + .../dsl/model/DeploymentsContextImpl.kt | 1 + .../boundary/dsl/model/PropertiesContext.kt | 11 +- .../dsl/model/PropertiesContextImpl.kt | 31 +- .../boundary/dsl/model/SimulationContext.kt | 14 - .../unibo/alchemist/model/nodes/TestNode.java | 9 +- .../boundary/properties/TestNodeProperty.kt | 5 +- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 245 +- .../it/unibo/alchemist/dsl/TestContents.kt | 10 +- .../it/unibo/alchemist/dsl/TestDeployments.kt | 13 +- .../it/unibo/alchemist/dsl/TestSimulations.kt | 11 +- .../it/unibo/alchemist/dsl/TestVariables.kt | 41 +- alchemist-maps/build.gradle.kts | 3 +- alchemist-physics/build.gradle.kts | 3 +- .../model/physics/reactions/PhysicsUpdate.kt | 3 +- .../TestEuclideanPhysics2DEnvironment.kt | 20 +- alchemist-smartcam/build.gradle.kts | 5 +- .../main/kotlin/dokka-convention.gradle.kts | 10 +- .../kotlin/kotlin-jvm-convention.gradle.kts | 10 + 55 files changed, 24981 insertions(+), 642 deletions(-) delete mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/InjectableConstructor.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/InjectableConstructor.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/TypePosition.kt create mode 100644 alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/AvailableIncarnations.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt diff --git a/alchemist-cognitive-agents/build.gradle.kts b/alchemist-cognitive-agents/build.gradle.kts index c0e8717d71..0176f274aa 100644 --- a/alchemist-cognitive-agents/build.gradle.kts +++ b/alchemist-cognitive-agents/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -15,6 +15,8 @@ plugins { } dependencies { + ksp(alchemist("dsl-processor")) + api(alchemist("api")) implementation(alchemist("euclidean-geometry")) diff --git a/alchemist-cognitive-agents/src/main/kotlin/it/unibo/alchemist/model/cognitive/steering/TypeBased.kt b/alchemist-cognitive-agents/src/main/kotlin/it/unibo/alchemist/model/cognitive/steering/TypeBased.kt index 43c146f086..bfcc2f3325 100644 --- a/alchemist-cognitive-agents/src/main/kotlin/it/unibo/alchemist/model/cognitive/steering/TypeBased.kt +++ b/alchemist-cognitive-agents/src/main/kotlin/it/unibo/alchemist/model/cognitive/steering/TypeBased.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -29,6 +29,6 @@ import kotlin.reflect.KClass class TypeBased( environment: Euclidean2DEnvironment, node: Node, - typeWeights: LinkedHashMap>, Double>, + typeWeights: Map>, Double>, defaultWeight: Double = 0.0, ) : Weighted(environment, node, { typeWeights[this::class] ?: defaultWeight }) diff --git a/alchemist-cognitive-agents/src/test/kotlin/it/unibo/alchemist/model/cognitive/TestSensory.kt b/alchemist-cognitive-agents/src/test/kotlin/it/unibo/alchemist/model/cognitive/TestSensory.kt index 84484654d3..7f8f0ef967 100644 --- a/alchemist-cognitive-agents/src/test/kotlin/it/unibo/alchemist/model/cognitive/TestSensory.kt +++ b/alchemist-cognitive-agents/src/test/kotlin/it/unibo/alchemist/model/cognitive/TestSensory.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -11,7 +11,6 @@ package it.unibo.alchemist.model.cognitive import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe -import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.SupportedIncarnations import it.unibo.alchemist.model.cognitive.properties.Pedestrian import it.unibo.alchemist.model.cognitive.properties.Perceptive2D @@ -31,14 +30,10 @@ import org.apache.commons.math3.random.RandomGenerator * * @param T used internally */ -class TestSensory : - StringSpec({ +class TestSensory : StringSpec({ - fun createHomogeneousPedestrian( - incarnation: Incarnation, - randomGenerator: RandomGenerator, - environment: Physics2DEnvironment, - ) = GenericNode(incarnation, environment).apply { + fun createHomogeneousPedestrian(randomGenerator: RandomGenerator, environment: Physics2DEnvironment) = + GenericNode(environment).apply { listOf( Pedestrian(randomGenerator, this), Social(this), @@ -47,32 +42,28 @@ class TestSensory : ).forEach(this::addProperty) } - "field of view" { - val environment = - ContinuousPhysics2DEnvironment( - SupportedIncarnations.get("protelis").orElseThrow(), - ) - val rand = MersenneTwister(1) - environment.linkingRule = NoLinks() - val incarnation: Incarnation = - SupportedIncarnations - .get(SupportedIncarnations.getAvailableIncarnations().first()) - .get() - val observed = createHomogeneousPedestrian(incarnation, rand, environment) - val origin = Euclidean2DPosition(5.0, 5.0) - environment.addNode(observed, origin) - val radius = 10.0 - origin.surrounding(radius).forEach { - with(createHomogeneousPedestrian(incarnation, rand, environment)) { - environment.addNode(this, it) - environment.setHeading(this, origin - it) - } + "field of view" { + val environment = + ContinuousPhysics2DEnvironment( + SupportedIncarnations.get("protelis").orElseThrow(), + ) + val rand = MersenneTwister(1) + environment.linkingRule = NoLinks() + val observed = createHomogeneousPedestrian(rand, environment) + val origin = Euclidean2DPosition(5.0, 5.0) + environment.addNode(observed, origin) + val radius = 10.0 + origin.surrounding(radius).forEach { + with(createHomogeneousPedestrian(rand, environment)) { + environment.addNode(this, it) + environment.setHeading(this, origin - it) } - environment.nodes.minusElement(observed).forEach { - with(FieldOfView2D(environment, it, radius, Math.PI / 2)) { - influentialNodes().size shouldBe 1 - influentialNodes().first() shouldBe observed - } + } + environment.nodes.minusElement(observed).forEach { + with(FieldOfView2D(environment, it, radius, Math.PI / 2)) { + influentialNodes().size shouldBe 1 + influentialNodes().first() shouldBe observed } } - }) + } +}) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 9dd01d5678..44608d7a15 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -21,17 +21,16 @@ import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSTypeParameter +import it.unibo.alchemist.boundary.dsl.processor.datatypes.InjectableConstructor import it.unibo.alchemist.boundary.dsl.processor.extensions.asString import it.unibo.alchemist.boundary.dsl.processor.extensions.injectableConstructors import it.unibo.alchemist.boundary.dsl.processor.extensions.nameOrTypeName -import it.unibo.alchemist.boundary.dsl.processor.extensions.typeName import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Reaction -import it.unibo.alchemist.model.TimeDistribution import java.io.PrintWriter import java.nio.charset.StandardCharsets import org.apache.commons.math3.random.RandomGenerator @@ -48,7 +47,7 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator) : SymbolProc .forEach { classDeclaration -> val injectableConstructors = classDeclaration.getConstructors() .flatMap { it.injectableConstructors() } - .toList() + .toSet() // Remove duplicates if (injectableConstructors.isNotEmpty()) { val file = codeGenerator.createNewFile( dependencies = classDeclaration.containingFile @@ -80,7 +79,6 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator) : SymbolProc resolver.getClassDeclarationByName(), resolver.getClassDeclarationByName>(), resolver.getClassDeclarationByName>(), - resolver.getClassDeclarationByName>(), ).map { checkNotNull(it).asStarProjectedType() }.toSet() private fun processConstructor( @@ -89,65 +87,71 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator) : SymbolProc injectableConstructor: InjectableConstructor, ) { val (constructor, injectableParams, preservedParams) = injectableConstructor - val context = injectableParams.joinToString(prefix = "context(", postfix = ")") { param -> - "${param.nameOrTypeName()}: ${param.type.asString()}" - } - writer.println(context) val typeParameters = constructor.typeParameters.render() - val parameters = preservedParams.joinToString(separator = NEWLINE_INDENT) { parameter -> - val vararg = if (parameter.isVararg) "vararg " else "" - "$vararg${parameter.name?.asString()}: ${parameter.type.asString()}" - } - val whereClause = constructor.typeParameters - .flatMap { typeParam -> - typeParam.bounds.map { bound -> - "${typeParam.simpleName.asString()} : ${bound.asString()}" - } + context(constructor.typeParameters.toSet()) { + val parameters = preservedParams.joinToString(separator = NEWLINE_INDENT) { parameter -> + val vararg = if (parameter.isVararg) "vararg " else "" + "$vararg${parameter.name?.asString()}: ${parameter.type.asString()}" } - .takeIf { it.isNotEmpty() } - ?.joinToString(separator = NEWLINE_INDENT, prefix = "where\n ", postfix = "\n") - .orEmpty() - val useAllArguments = preservedParams.size + injectableParams.size == constructor.parameters.size - val arguments = constructor.parameters.asSequence() - .run { - when { - useAllArguments -> this - else -> { - val argumentsToUse = (preservedParams + injectableParams).toSet() - filter { it in argumentsToUse } + val whereClause = constructor.typeParameters + .flatMap { typeParam -> + typeParam.bounds.map { bound -> + "${typeParam.simpleName.asString()} : ${bound.asString()}" } } - } - .joinToString(NEWLINE_INDENT) { - /* - * If it is a Java constructor, all arguments will be used. - * Since the same is true if there are no default parameters in Kotlin, - * it is safe to call positionally if `useAllArguments` is true. - * If it is a Kotlin constructor with default parameters, named arguments must be used to - * support cases in which there are mandatory parameters after the optional ones. - */ - val name = it.name - when { - useAllArguments || name == null -> { - "${if (it.isVararg) "*" else ""}${it.nameOrTypeName()}" + .takeIf { it.isNotEmpty() } + ?.joinToString(separator = NEWLINE_INDENT, prefix = "where\n ", postfix = "\n") + .orEmpty() + val useAllArguments = preservedParams.size + injectableParams.size == constructor.parameters.size + val arguments = constructor.parameters.asSequence() + .run { + when { + useAllArguments -> this + else -> { + val argumentsToUse = (preservedParams + injectableParams).toSet() + filter { it in argumentsToUse } + } } - else -> "${name.asString()} = ${it.nameOrTypeName()}" } + .joinToString(NEWLINE_INDENT) { + /* + * If it is a Java constructor, all arguments will be used. + * Since the same is true if there are no default parameters in Kotlin, + * it is safe to call positionally if `useAllArguments` is true. + * If it is a Kotlin constructor with default parameters, named arguments must be used to + * support cases in which there are mandatory parameters after the optional ones. + */ + val name = it.name + when { + useAllArguments || name == null -> { + "${if (it.isVararg) "*" else ""}${it.nameOrTypeName()}" + } + else -> "${name.asString()} = ${it.nameOrTypeName()}" + } + } + val context = injectableParams.joinToString(prefix = "context(", postfix = ")") { param -> + "${param.nameOrTypeName()}: ${param.type.asString()}" } - val functionName = classDeclaration.simpleName.asString().replaceFirstChar { it.lowercaseChar() } - val contextParameterNames = injectableParams.joinToString("") { param -> - param.nameOrTypeName().replaceFirstChar { it.uppercase() } - } - val argumentsString = if (parameters.isEmpty()) "()" else "(\n| $parameters\n|)" - writer.println( - """ + val classSimpleName = classDeclaration.simpleName.asString() + val functionName = classSimpleName.replaceFirstChar { it.lowercaseChar() } + val contextParameterNames = injectableParams.joinToString("") { param -> + param.nameOrTypeName().replaceFirstChar { it.uppercase() } + } + val argumentsString = if (parameters.isEmpty()) "()" else "(\n| $parameters\n|)" + writer.println( + """ + |/** + | * Contextual builder for [$classSimpleName]. + | */ |@JvmName("${functionName}WithContextual$contextParameterNames") - |fun $typeParameters$functionName$argumentsString $whereClause= ${classDeclaration.typeName}( + |$context + |fun $typeParameters$functionName$argumentsString $whereClause= ${classSimpleName}$typeParameters( | $arguments |) | - """.trimMargin(), - ) + """.trimMargin(), + ) + } } private fun List.render() = takeIf { it.isNotEmpty() } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/InjectableConstructor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/InjectableConstructor.kt deleted file mode 100644 index 6924d51212..0000000000 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/InjectableConstructor.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.processor - -import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import com.google.devtools.ksp.symbol.KSValueParameter - -internal data class InjectableConstructor( - val constructor: KSFunctionDeclaration, - val injectableParameters: List, - val preservedParameters: List, -) diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/InjectableConstructor.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/InjectableConstructor.kt new file mode 100644 index 0000000000..35f9d8e0d4 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/InjectableConstructor.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.datatypes + +import com.google.devtools.ksp.symbol.KSFunctionDeclaration +import com.google.devtools.ksp.symbol.KSType +import com.google.devtools.ksp.symbol.KSValueParameter + +internal data class InjectableConstructor( + val constructor: KSFunctionDeclaration, + val injectableParameters: List, + val preservedParameters: List, +) { + val returnType: KSType? by lazy { constructor.returnType?.resolve() } + val injectableTypes by lazy { injectableParameters.map { it.type.resolve() } } + val preservedTypes by lazy { preservedParameters.map { it.type.resolve() } } + + override fun toString(): String = "InjectableConstructor(${returnType?.toString()}, " + + "injectableParameters=${injectableParameters.typedAsString()}, " + + "preservedParameters=${preservedParameters.typedAsString()}" + + private fun List.typedAsString(): String = this.zip(this.map { it.type.resolve() }) + .joinToString(", ", prefix = "[", postfix = "]") { (param, type) -> "${param.name?.asString()}: $type" } + + override fun equals(other: Any?): Boolean = other is InjectableConstructor && + other.returnType == returnType && + other.injectableTypes == injectableTypes && + other.preservedTypes == preservedTypes + + override fun hashCode(): Int = listOf( + returnType, + injectableTypes, + preservedTypes, + ).hashCode() +} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/TypePosition.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/TypePosition.kt new file mode 100644 index 0000000000..7b272182b7 --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/TypePosition.kt @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.datatypes + +internal enum class TypePosition { TYPE, TYPE_ARG } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt index cca2598906..9da640e2b3 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -13,7 +13,7 @@ import com.google.devtools.ksp.isPublic import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.google.devtools.ksp.symbol.KSType -import it.unibo.alchemist.boundary.dsl.processor.InjectableConstructor +import it.unibo.alchemist.boundary.dsl.processor.datatypes.InjectableConstructor /** * Finds a public constructor for the given class declaration. diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt new file mode 100644 index 0000000000..51c2686d1d --- /dev/null +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.processor.extensions + +import com.google.devtools.ksp.symbol.KSTypeArgument +import com.google.devtools.ksp.symbol.KSTypeParameter +import com.google.devtools.ksp.symbol.Variance +import it.unibo.alchemist.boundary.dsl.processor.datatypes.TypePosition + +context(valid: Set) +internal fun KSTypeArgument.renderAsTypeArg(substitutions: Map): String = + when (val refType = type) { + null -> "*" + else -> when (variance) { + Variance.STAR -> "*" + Variance.COVARIANT -> "out ${refType.resolve().render(TypePosition.TYPE, substitutions)}" + Variance.CONTRAVARIANT -> "in ${refType.resolve().render(TypePosition.TYPE, substitutions)}" + Variance.INVARIANT -> refType.resolve().render(TypePosition.TYPE, substitutions) + } + } diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt index e7cc1e85c7..d9061d8860 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -9,9 +9,56 @@ package it.unibo.alchemist.boundary.dsl.processor.extensions +import com.google.devtools.ksp.innerArguments import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSType +import com.google.devtools.ksp.symbol.KSTypeAlias +import com.google.devtools.ksp.symbol.KSTypeArgument +import com.google.devtools.ksp.symbol.KSTypeParameter import it.unibo.alchemist.boundary.dsl.processor.DslBuilderProcessor +import it.unibo.alchemist.boundary.dsl.processor.datatypes.TypePosition context(resolver: Resolver) internal fun KSType.isInjectable() = DslBuilderProcessor.injectableTypes().any { it.isAssignableFrom(this) } + +context(valid: Set) +internal fun KSType.render( + position: TypePosition, + substitutions: Map = emptyMap(), +): String = buildString { + when (val typedDeclaration = declaration) { + is KSTypeAlias -> { + // map alias params -> use-site args, then render RHS under that substitution + val aliasMap = declaration.typeParameters.zip(arguments).toMap() + val expanded = typedDeclaration.type.resolve() + append(expanded.render(position, substitutions + aliasMap)) + } + is KSTypeParameter -> { + val replacement = substitutions[typedDeclaration] + when { + replacement != null -> append(replacement.renderAsTypeArg(substitutions)) + typedDeclaration in valid -> append(declaration.simpleName.asString()) + position == TypePosition.TYPE_ARG -> append("*") + else -> { + // fallback for non-arg position (avoid emitting bare '*', which is illegal) + val fallback = typedDeclaration.bounds.firstOrNull()?.resolve() + append(fallback?.render(TypePosition.TYPE, substitutions) ?: "Any?") + } + } + } + is KSClassDeclaration -> { + append(typedDeclaration.typeName) + // Protect against mismatched counts (inner classes / typealias quirks): + val declParamCount = typedDeclaration.typeParameters.size + val args = (this@render.innerArguments.ifEmpty { this@render.arguments }) + .take(declParamCount) + if (args.isNotEmpty()) { + append(args.joinToString(prefix = "<", postfix = ">") { it.renderAsTypeArg(substitutions) }) + } + } + else -> error("Unsupported type: $typedDeclaration") + } + + if (isMarkedNullable) append("?") +} diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt index 4ee9e68743..df115e6ba3 100644 --- a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt +++ b/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -11,21 +11,7 @@ package it.unibo.alchemist.boundary.dsl.processor.extensions import com.google.devtools.ksp.symbol.KSTypeParameter import com.google.devtools.ksp.symbol.KSTypeReference +import it.unibo.alchemist.boundary.dsl.processor.datatypes.TypePosition -internal fun KSTypeReference.asString(): String = buildString { - val type = resolve() - when (val declaration = type.declaration) { - is KSTypeParameter -> append(declaration.simpleName.asString()) - else -> append(declaration.typeName) - } - if (type.arguments.isNotEmpty()) { - append( - type.arguments.joinToString(prefix = "<", postfix = ">") { - it.type?.asString() ?: "*" - }, - ) - } - if (type.isMarkedNullable) { - append("?") - } -} +context(valid: Set) +internal fun KSTypeReference.asString(): String = resolve().render(TypePosition.TYPE) diff --git a/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/TestConcurrency.kt b/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/TestConcurrency.kt index 3ec5d40559..d0dcf3841d 100644 --- a/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/TestConcurrency.kt +++ b/alchemist-engine/src/test/kotlin/it/unibo/alchemist/core/TestConcurrency.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -36,7 +36,7 @@ internal class TestConcurrency { fun `simulation commands should interleave`() { val incarnation = BiochemistryIncarnation() val environment = Continuous2DEnvironment(incarnation) - val node = GenericNode(incarnation, environment) + val node = GenericNode(environment) environment.linkingRule = NoLinks() val timeDistribution = DiracComb(1.0) val reaction = Event(node, timeDistribution) diff --git a/alchemist-euclidean-geometry/build.gradle.kts b/alchemist-euclidean-geometry/build.gradle.kts index 8fd5b458fb..39cf748cff 100644 --- a/alchemist-euclidean-geometry/build.gradle.kts +++ b/alchemist-euclidean-geometry/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -15,6 +15,8 @@ plugins { } dependencies { + ksp(alchemist("dsl-processor")) + api(alchemist("api")) api(alchemist("implementationbase")) api(libs.dyn4j) diff --git a/alchemist-euclidean-geometry/src/test/java/it/unibo/alchemist/model/obstacles/TestContinuous2DObstacle.java b/alchemist-euclidean-geometry/src/test/java/it/unibo/alchemist/model/obstacles/TestContinuous2DObstacle.java index 76c81b82f0..021392acc6 100644 --- a/alchemist-euclidean-geometry/src/test/java/it/unibo/alchemist/model/obstacles/TestContinuous2DObstacle.java +++ b/alchemist-euclidean-geometry/src/test/java/it/unibo/alchemist/model/obstacles/TestContinuous2DObstacle.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -33,7 +33,7 @@ private Node createIntNode( final Incarnation incarnation, final Environment environment ) { - return new GenericNode<>(incarnation, environment) { + return new GenericNode<>(environment) { @Override public Integer createT() { return 0; diff --git a/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/neighborhoods/TestNeighborhood.kt b/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/neighborhoods/TestNeighborhood.kt index a1f7e7d0b9..1f240f49a7 100644 --- a/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/neighborhoods/TestNeighborhood.kt +++ b/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/neighborhoods/TestNeighborhood.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.neighborhoods import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.SupportedIncarnations import it.unibo.alchemist.model.environments.Continuous2DEnvironment @@ -22,12 +21,10 @@ import org.junit.jupiter.api.Test * Tests pertaining to the `it.unibo.alchemist.model.implementations.neighborhoods` package. */ class TestNeighborhood { - private fun createIntNode( - incarnation: Incarnation, - environment: Environment, - ): Node = object : GenericNode(incarnation, environment) { - override fun createT(): Int = 0 - } + private fun createIntNode(environment: Environment): Node = + object : GenericNode(environment) { + override fun createT(): Int = 0 + } /** * Tests whether the clone function of the @@ -37,8 +34,8 @@ class TestNeighborhood { fun testClone() { val incarnation = SupportedIncarnations.get("protelis").orElseThrow() val environment = Continuous2DEnvironment(incarnation) - val n1 = createIntNode(incarnation, environment) - val n2 = createIntNode(incarnation, environment) + val n1 = createIntNode(environment) + val n2 = createIntNode(environment) val neigh1 = Neighborhoods.make(environment, n1, mutableListOf(n2)) val neigh2 = neigh1.remove(n2) Assertions.assertEquals(0, neigh2.size()) diff --git a/alchemist-implementationbase/build.gradle.kts b/alchemist-implementationbase/build.gradle.kts index ad20c4a61c..068b900bbb 100644 --- a/alchemist-implementationbase/build.gradle.kts +++ b/alchemist-implementationbase/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -14,6 +14,8 @@ plugins { } dependencies { + ksp(alchemist("dsl-processor")) + api(alchemist("api")) api(alchemist("maintenance-tooling")) api(libs.apache.commons.math3) diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/nodes/GenericNode.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/nodes/GenericNode.kt index 682602a9e7..f4b8715ebc 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/nodes/GenericNode.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/nodes/GenericNode.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -10,7 +10,6 @@ package it.unibo.alchemist.model.nodes import com.google.common.collect.MapMaker import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Molecule import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.NodeProperty @@ -32,10 +31,6 @@ import javax.annotation.Nonnull open class GenericNode @JvmOverloads constructor( - /** - * simulation incarnation. - */ - val incarnation: Incarnation, /** * The environment in which the node is places. */ @@ -48,9 +43,6 @@ constructor( val molecules: MutableMap = LinkedHashMap(), final override val properties: MutableList> = ArrayList(), ) : Node { - constructor( - environment: Environment, - ) : this(environment.incarnation, environment) final override fun addReaction(reactionToAdd: Reaction) { reactions.add(reactionToAdd) @@ -69,7 +61,7 @@ constructor( /** * @return an empty concentration */ - protected open fun createT(): T = incarnation.createConcentration() + protected open fun createT(): T = environment.incarnation.createConcentration() final override fun equals(other: Any?): Boolean = other is Node<*> && other.id == id diff --git a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt index ff83559197..a9af66138e 100644 --- a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt +++ b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -23,7 +23,7 @@ import kotlin.test.assertTrue * Adds a node to the environment at the specified [coordinates]. */ infix fun Environment.addNodeAt(coordinates: Pair) = addNode( - GenericNode(ProtelisIncarnation(), this), + GenericNode(this), Euclidean2DPosition(coordinates.first, coordinates.second), ) diff --git a/alchemist-incarnation-biochemistry/build.gradle.kts b/alchemist-incarnation-biochemistry/build.gradle.kts index 6fb3df97cd..49ad5a69b7 100644 --- a/alchemist-incarnation-biochemistry/build.gradle.kts +++ b/alchemist-incarnation-biochemistry/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -24,14 +24,20 @@ plugins { dependencies { antlr(libs.antlr4) + + ksp(alchemist("dsl-processor")) + api(alchemist("implementationbase")) api(alchemist("euclidean-geometry")) api(alchemist("physics")) + implementation(libs.apache.commons.lang3) implementation(libs.boilerplate) implementation(libs.jirf) implementation(libs.trove4j) + runtimeOnly(libs.antlr4.runtime) + testImplementation(alchemist("engine")) testImplementation(alchemist("loading")) } diff --git a/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/BiochemistryIncarnation.java b/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/BiochemistryIncarnation.java index 584892a168..4e09ffaf56 100644 --- a/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/BiochemistryIncarnation.java +++ b/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/BiochemistryIncarnation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -59,7 +59,7 @@ public Node createNode( if (Double.isNaN(diameter)) { throw new IllegalArgumentException("Invalid diameter: " + parameter); } - final Node node = new GenericNode<>(this, environment); + final Node node = new GenericNode<>(environment); if (diameter == 0) { node.addProperty(new CircularCell(environment, node)); } else { diff --git a/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/nodes/EnvironmentNodeImpl.java b/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/nodes/EnvironmentNodeImpl.java index 4923333138..7b27c9c6d4 100644 --- a/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/nodes/EnvironmentNodeImpl.java +++ b/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/nodes/EnvironmentNodeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -10,7 +10,6 @@ package it.unibo.alchemist.model.biochemistry.nodes; import it.unibo.alchemist.model.Environment; -import it.unibo.alchemist.model.Incarnation; import it.unibo.alchemist.model.Molecule; import it.unibo.alchemist.model.biochemistry.EnvironmentNode; import it.unibo.alchemist.model.nodes.GenericNode; @@ -26,23 +25,13 @@ public final class EnvironmentNodeImpl extends GenericNode implements En @Serial private static final long serialVersionUID = 1L; - /** - * Create a new environment node. - * - * @param incarnation the simulation incarnation - * @param environment the environment - */ - public EnvironmentNodeImpl(final Incarnation incarnation, final Environment environment) { - super(incarnation, environment); - } - /** * Create a new environment node. * * @param environment the environment */ public EnvironmentNodeImpl(final Environment environment) { - super(environment.getIncarnation(), environment); + super(environment); } @Override diff --git a/alchemist-incarnation-biochemistry/src/test/java/it/unibo/alchemist/model/biochemistry/properties/TestDeformableCell.java b/alchemist-incarnation-biochemistry/src/test/java/it/unibo/alchemist/model/biochemistry/properties/TestDeformableCell.java index 1b2bd94faf..d06cbaf9a9 100644 --- a/alchemist-incarnation-biochemistry/src/test/java/it/unibo/alchemist/model/biochemistry/properties/TestDeformableCell.java +++ b/alchemist-incarnation-biochemistry/src/test/java/it/unibo/alchemist/model/biochemistry/properties/TestDeformableCell.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -80,7 +80,7 @@ class TestDeformableCell { private TimeDistribution time; private Node createDeformableCell(final double maxDiameter, final double rigidity) { - final Node node = new GenericNode<>(incarnation, environment); + final Node node = new GenericNode<>(environment); node.addProperty( new CircularDeformableCell(environment, node, maxDiameter, rigidity) ); diff --git a/alchemist-incarnation-protelis/build.gradle.kts b/alchemist-incarnation-protelis/build.gradle.kts index 3286a1e7c2..35417fc9ab 100644 --- a/alchemist-incarnation-protelis/build.gradle.kts +++ b/alchemist-incarnation-protelis/build.gradle.kts @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + import Libs.alchemist /* @@ -14,6 +23,8 @@ plugins { } dependencies { + // KSP + ksp(alchemist("dsl-processor")) // API api(alchemist("api")) api(alchemist("implementationbase")) diff --git a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/ProtelisIncarnation.kt b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/ProtelisIncarnation.kt index 7b1938bc8b..21cdbe71cc 100644 --- a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/ProtelisIncarnation.kt +++ b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/ProtelisIncarnation.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -177,7 +177,7 @@ class ProtelisIncarnation

> : Incarnation { randomGenerator: RandomGenerator, environment: Environment, parameter: Any?, - ): Node = GenericNode(this, environment).apply { + ): Node = GenericNode(environment).apply { addProperty(ProtelisDevice(environment, this)) } diff --git a/alchemist-incarnation-sapere/build.gradle.kts b/alchemist-incarnation-sapere/build.gradle.kts index 129508c494..dbe59f9401 100644 --- a/alchemist-incarnation-sapere/build.gradle.kts +++ b/alchemist-incarnation-sapere/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -14,11 +14,12 @@ plugins { } dependencies { + ksp(alchemist("dsl-processor")) api(alchemist("api")) + api(alchemist("sapere-mathexp")) implementation(alchemist("implementationbase")) implementation(alchemist("maps")) implementation(alchemist("physics")) - implementation(alchemist("sapere-mathexp")) implementation(libs.boilerplate) implementation(libs.trove4j) } diff --git a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/SAPEREIncarnation.java b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/SAPEREIncarnation.java index 0c3cdb9cf9..7f162fbff4 100644 --- a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/SAPEREIncarnation.java +++ b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/SAPEREIncarnation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -274,20 +274,21 @@ public Action> createAction( final var parameters = additionalParameters.toString(); if (parameters.startsWith("+")) { return new LsaRandomNeighborAction( - (LsaNode) node, - createMolecule(parameters.substring(1)), + randomGenerator, environment, - randomGenerator + (LsaNode) node, + createMolecule(parameters.substring(1)) ); } if (parameters.startsWith("*")) { return new LsaAllNeighborsAction( + randomGenerator, + environment, (LsaNode) node, - createMolecule(parameters.substring(1)), - environment + createMolecule(parameters.substring(1)) ); } - return new LsaStandardAction(createMolecule(parameters), (LsaNode) node, randomGenerator); + return new LsaStandardAction(randomGenerator, (LsaNode) node, createMolecule(parameters)); } @Override diff --git a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaAllNeighborsAction.java b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaAllNeighborsAction.java index 89f1c080d2..481cb99f00 100644 --- a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaAllNeighborsAction.java +++ b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaAllNeighborsAction.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -29,22 +29,6 @@ public final class LsaAllNeighborsAction extends LsaRandomNeighborAction { @Serial private static final long serialVersionUID = -4798752202640197182L; - /** - * @param node - * the node in which the reaction is programmed - * @param molecule - * the LSA - * @param environment - * the current environment - */ - public LsaAllNeighborsAction( - final ILsaNode node, - final ILsaMolecule molecule, - final Environment, ?> environment - ) { - this(node, molecule, environment, null); - } - /** * @param node * the node in which the reaction is programmed @@ -56,12 +40,12 @@ public LsaAllNeighborsAction( * unused. Can be null. */ public LsaAllNeighborsAction( - final ILsaNode node, - final ILsaMolecule molecule, - final Environment, ?> environment, - final RandomGenerator randomGenerator + final RandomGenerator randomGenerator, + final Environment, ?> environment, + final ILsaNode node, + final ILsaMolecule molecule ) { - super(node, molecule, environment, randomGenerator); + super(randomGenerator, environment, node, molecule); } @Override diff --git a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaRandomNeighborAction.java b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaRandomNeighborAction.java index cb72c1bff5..0f5bddfc85 100644 --- a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaRandomNeighborAction.java +++ b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaRandomNeighborAction.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -63,12 +63,12 @@ public class LsaRandomNeighborAction extends LsaStandardAction { */ @SuppressWarnings("unchecked") public LsaRandomNeighborAction( - final ILsaNode node, - final ILsaMolecule molecule, - final Environment, ?> environment, - final RandomGenerator randomGenerator + final RandomGenerator randomGenerator, + final Environment, ?> environment, + final ILsaNode node, + final ILsaMolecule molecule ) { - super(molecule, node); + super(randomGenerator, node, molecule); final String molString = molecule.toString(); initO = molString.contains(LsaMolecule.SYN_O); initD = molString.contains(LsaMolecule.SYN_D); @@ -88,7 +88,7 @@ public LsaRandomNeighborAction cloneAction( final Node> node, final Reaction> reaction ) { - return new LsaRandomNeighborAction((ILsaNode) node, getMolecule(), getEnvironment(), randomEngine); + return new LsaRandomNeighborAction(randomEngine, getEnvironment(), (ILsaNode) node, getMolecule()); } /** diff --git a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaStandardAction.java b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaStandardAction.java index 7998c6487b..e74440323f 100644 --- a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaStandardAction.java +++ b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/actions/LsaStandardAction.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -48,19 +48,6 @@ public class LsaStandardAction extends AbstractLsaAction { ) private final RandomGenerator rand; - /** - * Builds a new local action, without any RandomGenerator. #RANDOM. - * - * @param n - * The source node - * @param m - * The ILsaMolecule instance you want to add to the node lsa - * space. - */ - public LsaStandardAction(final ILsaMolecule m, final ILsaNode n) { - this(m, n, null); - } - /** * Builds a new local action. * @@ -72,7 +59,7 @@ public LsaStandardAction(final ILsaMolecule m, final ILsaNode n) { * @param random * The Random generator to use */ - public LsaStandardAction(final ILsaMolecule m, final ILsaNode n, final RandomGenerator random) { + public LsaStandardAction(final RandomGenerator random, final ILsaNode n, final ILsaMolecule m) { super(n, Collections.singletonList(m)); mol = Objects.requireNonNull(m); rand = random; @@ -94,7 +81,7 @@ public LsaStandardAction(final ILsaMolecule m, final ILsaNode n, final RandomGen */ @Override public LsaStandardAction cloneAction(final Node> node, final Reaction> reaction) { - return new LsaStandardAction(getMolecule(), (ILsaNode) node); + return new LsaStandardAction(rand, (ILsaNode) node, getMolecule()); } /** diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/ScafiIncarnation.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/ScafiIncarnation.scala index 642caaa914..1384e5b2f1 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/ScafiIncarnation.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/ScafiIncarnation.scala @@ -1,5 +1,6 @@ /* - * Copyright (C) 2010-2019, Danilo Pianini and contributors listed in the main project's alchemist/build.gradle file. + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the * GNU General Public License, with a linking exception, @@ -139,7 +140,7 @@ sealed class ScafiIncarnation[T, P <: Position[P]] extends Incarnation[T, P] { environment: Environment[T, P], parameters: Any ): GenericNode[T] = { - val scafiNode = new GenericNode[T](this, environment) + val scafiNode = new GenericNode[T](environment) scafiNode.addProperty(new ScafiDevice(scafiNode)) scafiNode } diff --git a/alchemist-loading/build.gradle.kts b/alchemist-loading/build.gradle.kts index f2bdf99cca..9e0935022d 100644 --- a/alchemist-loading/build.gradle.kts +++ b/alchemist-loading/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -19,7 +19,6 @@ import Libs.incarnation */ plugins { id("kotlin-jvm-convention") - alias(libs.plugins.ksp) } dependencies { @@ -53,11 +52,11 @@ dependencies { testImplementation(alchemist("engine")) testImplementation(alchemist("maps")) testImplementation(alchemist("test")) + testImplementation(incarnation("sapere")) + testImplementation(incarnation("protelis")) testImplementation(libs.appdirs) testImplementation(libs.caffeine) testImplementation(libs.embedmongo) - testRuntimeOnly(incarnation("sapere")) - testRuntimeOnly(incarnation("protelis")) implementation(kotlin("script-runtime")) ksp(project(":alchemist-dsl-processor")) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt index 9964889d3b..d6981917f1 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt @@ -25,10 +25,10 @@ import java.util.concurrent.Semaphore * * @param ctx The simulation context. */ -abstract class DSLLoader>( - private val ctx: SimulationContext<*, *>, - private val envFactory: () -> Environment<*, *>, -) : Loader { +abstract class DSLLoader(private val ctx: SimulationContext<*, *>) : Loader { + + protected abstract fun > envFactory(): Environment + override fun > getWith(values: Map): Simulation = SingleUseLoader(ctx).load(values) private inner class SingleUseLoader(private val ctx: SimulationContext<*, *>) { @@ -45,7 +45,7 @@ abstract class DSLLoader>( mutex.release() } val typedCtx = ctx as SimulationContextImpl - val envInstance = envFactory() as Environment + val envInstance = envFactory() val unknownVariableNames = values.keys - this@DSLLoader.variables.keys require(unknownVariableNames.isEmpty()) { "Unknown variables provided: $unknownVariableNames." + diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index b18e3906d9..e617698bd7 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -13,16 +13,13 @@ import it.unibo.alchemist.boundary.DependentVariable import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations as Inc import it.unibo.alchemist.boundary.dsl.model.SimulationContext import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.SupportedIncarnations import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.positions.Euclidean2DPosition -import kotlin.jvm.optionals.getOrElse import org.apache.commons.math3.random.RandomGenerator /** @@ -50,23 +47,16 @@ object Dsl { fun > createLoader( builder: SimulationContext, envBuilder: () -> Environment, - ): Loader = object : DSLLoader(builder, envBuilder) { + ): Loader = object : DSLLoader(builder) { override val constants: Map = emptyMap() override val dependentVariables: Map> = emptyMap() override val variables: Map> = builder.variablesContext.variables override val remoteDependencies: List = emptyList() override val launcher: Launcher = builder.launcher - } - /** - * Converts an Incarnation enum to an Incarnation instance. - * - * @return The incarnation instance. - */ - fun > Inc.incarnation(): Incarnation = - SupportedIncarnations.get(this.name).getOrElse { - throw IllegalArgumentException("Incarnation $this not supported") - } + @Suppress("UNCHECKED_CAST") + override fun > envFactory(): Environment = envBuilder() as Environment + } /** * Creates a simulation with a custom environment. @@ -78,20 +68,23 @@ object Dsl { */ fun > simulation( incarnation: Incarnation, - environment: () -> Environment, + environment: context(Incarnation) () -> Environment, block: context( RandomGenerator, Environment ) SimulationContext.() -> Unit, ): Loader { val ctx = SimulationContextImpl(incarnation) - @Suppress("UNCHECKED_CAST") ctx.apply { context(ctx.simulationGenerator, ctx.environment) { block() } } - return createLoader(ctx, environment) + return createLoader(ctx) { + context(incarnation) { + environment() + } + } } /** @@ -109,10 +102,8 @@ object Dsl { Environment ) SimulationContext.() -> Unit, ): Loader { - @Suppress("UNCHECKED_CAST") val defaultEnv = { Continuous2DEnvironment(incarnation) } val ctx = SimulationContextImpl(incarnation) - @Suppress("UNCHECKED_CAST") ctx.apply { context(incarnation, ctx.simulationGenerator, ctx.environment) { block() diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/AvailableIncarnations.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/AvailableIncarnations.kt deleted file mode 100644 index 43ffe0ce0c..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/AvailableIncarnations.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -/** - * Enumeration of available Alchemist incarnations. - */ -enum class AvailableIncarnations { - /** - * SAPERE incarnation. - */ - SAPERE, - - /** - * PROTELIS incarnation. - */ - PROTELIS, - - /** - * SCAFI incarnation. - */ - SCAFI, - - /** - * BIOCHEMISTRY incarnation. - */ - BIOCHEMISTRY, -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt new file mode 100644 index 0000000000..ea510e2a4d --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt @@ -0,0 +1,24345 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.PositionBasedFilter + +/** + * Context interface for configuring node content (molecules and concentrations). + * + * This context is used within [DeploymentContext] blocks to define the initial + * content of nodes deployed at specific positions. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [it.unibo.alchemist.model.Position]. + * + * @see [DeploymentContext] for the parent context + * @see [it.unibo.alchemist.model.Incarnation.createMolecule] + * @see [it.unibo.alchemist.model.Incarnation.createConcentration] + */ +interface ContentContext> { + /** + * The optional position filter applied to this content context. + * + * If set, content is only applied to nodes at positions matching this filter. + */ + val filter: PositionBasedFilter

? + + /** + * The molecule name to inject into nodes. + * + * The molecule is created using the incarnation's molecule factory. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * @see [it.unibo.alchemist.model.Incarnation.createMolecule] + */ + var molecule: String? + + /** + * The concentration value for the molecule. + * + * The concentration is created using the incarnation's concentration factory. + * + * @see [it.unibo.alchemist.model.Incarnation.createConcentration] + */ + var concentration: T? +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt index 36efda469e..944ceea5e3 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt @@ -9,91 +9,10 @@ package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.boundary.dsl.AlchemistDsl -import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter -import org.apache.commons.math3.random.RandomGenerator - -/** - * Context interface for managing node deployments in a simulation. - * - * Deployments define where nodes are placed in the environment and can be configured - * with content (molecules and concentrations), programs (reactions), and properties. - * - * ## Usage Example - * - * ```kotlin - * simulation(incarnation) { - * deployments { - * deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.25)) { - * all { - * molecule = "token" - * concentration = 1.0 - * } - * programs { - * all { - * program = "{token} --> {firing}" - * } - * } - * } - * } - * } - * ``` - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - * - * @see [SimulationContext.deployments] for configuring deployments in a simulation - * @see [Deployment] for the deployment interface - * @see [DeploymentContext] for configuring individual deployments - */ -@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -interface DeploymentsContext> { - /** - * The simulation context this deployments context belongs to. - */ - val ctx: SimulationContext - - /** - * The random number generator for scenario generation. - * - * Used for random deployments and position perturbations. - * - * @see [RandomGenerator] - */ - val generator: RandomGenerator - - /** - * Deploys nodes using a deployment with a configuration block. - * - * The configuration block allows setting content, programs, properties, and custom node factories. - * - * ```kotlin - * deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.25)) { - * all { molecule = "token" } - * } - * ``` - * - * @param deployment The deployment that defines node positions. - * @param block The configuration block for the deployment. - * @see [Deployment] - */ - fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) - - /** - * Deploys nodes using a deployment without additional configuration. - * - * Nodes are created at the positions defined by the deployment with default settings. - * - * @param deployment The deployment that defines node positions. - * @see [Deployment] - */ - context(environment: Environment) - fun deploy(deployment: Deployment<*>) -} /** * Context interface for configuring a single deployment. @@ -109,6 +28,8 @@ interface DeploymentsContext> { * @see [ProgramsContext] for configuring node programs * @see [PropertiesContext] for configuring node properties */ +// TODO: remove when detekt false positive is fixed +@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters interface DeploymentContext> { /** * The deployments context this deployment context belongs to. @@ -182,6 +103,7 @@ interface DeploymentContext> { * @see [Node] * @see [it.unibo.alchemist.model.Incarnation.createNode] */ + context(environment: Environment) fun nodes(factory: (DeploymentContext) -> Node) /** @@ -202,43 +124,3 @@ interface DeploymentContext> { */ fun properties(block: PropertiesContext.() -> Unit) } - -/** - * Context interface for configuring node content (molecules and concentrations). - * - * This context is used within [DeploymentContext] blocks to define the initial - * content of nodes deployed at specific positions. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - * - * @see [DeploymentContext] for the parent context - * @see [it.unibo.alchemist.model.Incarnation.createMolecule] - * @see [it.unibo.alchemist.model.Incarnation.createConcentration] - */ -interface ContentContext> { - /** - * The optional position filter applied to this content context. - * - * If set, content is only applied to nodes at positions matching this filter. - */ - val filter: PositionBasedFilter

? - - /** - * The molecule name to inject into nodes. - * - * The molecule is created using the incarnation's molecule factory. - * - * @see [it.unibo.alchemist.model.Incarnation.createMolecule] - */ - var molecule: String? - - /** - * The concentration value for the molecule. - * - * The concentration is created using the incarnation's concentration factory. - * - * @see [it.unibo.alchemist.model.Incarnation.createConcentration] - */ - var concentration: T? -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt new file mode 100644 index 0000000000..6daf6624d2 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Position +import org.apache.commons.math3.random.RandomGenerator + +/** + * Context interface for managing node deployments in a simulation. + * + * Deployments define where nodes are placed in the environment and can be configured + * with content (molecules and concentrations), programs (reactions), and properties. + * + * ## Usage Example + * + * ```kotlin + * simulation(incarnation) { + * deployments { + * deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.25)) { + * all { + * molecule = "token" + * concentration = 1.0 + * } + * programs { + * all { + * program = "{token} --> {firing}" + * } + * } + * } + * } + * } + * ``` + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [it.unibo.alchemist.model.Position]. + * + * @see [SimulationContext.deployments] for configuring deployments in a simulation + * @see [it.unibo.alchemist.model.Deployment] for the deployment interface + * @see [DeploymentContext] for configuring individual deployments + */ +@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters +interface DeploymentsContext> { + /** + * The simulation context this deployments context belongs to. + */ + val ctx: SimulationContext + + /** + * The random number generator for scenario generation. + * + * Used for random deployments and position perturbations. + * + * @see [org.apache.commons.math3.random.RandomGenerator] + */ + val generator: RandomGenerator + + /** + * Deploys nodes using a deployment with a configuration block. + * + * The configuration block allows setting content, programs, properties, and custom node factories. + * + * ```kotlin + * deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.25)) { + * all { molecule = "token" } + * } + * ``` + * + * @param deployment The deployment that defines node positions. + * @param block The configuration block for the deployment. + * @see [it.unibo.alchemist.model.Deployment] + */ + fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) + + /** + * Deploys nodes using a deployment without additional configuration. + * + * Nodes are created at the positions defined by the deployment with default settings. + * + * @param deployment The deployment that defines node positions. + * @see [Deployment] + */ + context(environment: Environment) + fun deploy(deployment: Deployment<*>) +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt index ec1690371d..e6c823cabe 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt @@ -146,6 +146,7 @@ open class DeploymentsContextImpl>(override val ctx: Simulati programsContext.apply(block) } + context(environment: Environment) override fun nodes(factory: DeploymentContext.() -> Node) { nodeFactory = factory } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt index fd237670d6..d5db4c3f69 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -10,6 +10,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.dsl.AlchemistDsl +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.NodeProperty import it.unibo.alchemist.model.Position @@ -62,14 +63,17 @@ interface PropertiesContext> { * @param block The property configuration block. * @see [PositionBasedFilter] */ - fun inside(filter: PositionBasedFilter<*>, block: PropertyContext.() -> Unit) + fun inside( + filter: PositionBasedFilter

, + block: context(Environment, Node) PropertyContext.() -> Unit, + ) /** * Configures properties for all nodes in the deployment. * * @param block The property configuration block. */ - fun all(block: PropertyContext.() -> Unit) + fun all(block: context(Environment, Node) PropertyContext.() -> Unit) } /** @@ -103,7 +107,6 @@ interface PropertyContext> { /** * Adds a property to the node. * - * @param property The property to add to the node. * @see [NodeProperty] */ operator fun NodeProperty.unaryPlus() diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt index cbe494b978..f6d5c2c8c5 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt @@ -1,6 +1,16 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.NodeProperty import it.unibo.alchemist.model.Position @@ -16,16 +26,23 @@ class PropertiesContextImpl>(override val ctx: DeploymentCont /** * List of property contexts with their associated filters. */ - val propertiesCtx: MutableList Unit, PositionBasedFilter

?>> = mutableListOf() + val propertiesCtx: MutableList< + Pair< + context(Environment, Node) + PropertyContext.() -> Unit, + PositionBasedFilter

?, + >, + > = mutableListOf() - override fun inside(filter: PositionBasedFilter<*>, block: PropertyContext.() -> Unit) { - @Suppress("UNCHECKED_CAST") - val typedFilter = filter as PositionBasedFilter

- propertiesCtx.add(block to typedFilter) - logger.debug("Adding property for nodes inside filter: {}", typedFilter) + override fun inside( + filter: PositionBasedFilter

, + block: context(Environment, Node) PropertyContext.() -> Unit, + ) { + propertiesCtx.add(block to filter) + logger.debug("Adding property for nodes inside filter: {}", filter) } - override fun all(block: PropertyContext.() -> Unit) { + override fun all(block: context(Environment, Node) PropertyContext.() -> Unit) { propertiesCtx.add(block to null) logger.debug("Adding property for all nodes") } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index e370afe118..4c00366344 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -12,7 +12,6 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GlobalReaction import it.unibo.alchemist.model.Incarnation @@ -59,20 +58,7 @@ interface SimulationContext> { /** * The incarnation instance that defines how molecules, nodes, and reactions are created. * - * ## Creating an Incarnation - * - * Incarnations are created from the [AvailableIncarnations] enum using the extension function: - * ```kotlin - * - * simulation(AvailableIncarnations.SAPERE.incarnation(), environment) { - * // simulation configuration - * } - * ``` - * - * - * @see [AvailableIncarnations] for the DSL enum of available incarnations * @see [Incarnation] for the incarnation interface - * @see [it.unibo.alchemist.boundary.dsl.Dsl.incarnation] for converting enum to instance */ val incarnation: Incarnation diff --git a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java index 61b9b48f86..b7c1fdaaa4 100644 --- a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java +++ b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java @@ -16,7 +16,7 @@ /** * Generic node for testing purposes. */ -public final class TestNode extends GenericNode { +public final class TestNode extends GenericNode { @Serial private static final long serialVersionUID = 1L; @@ -24,13 +24,14 @@ public final class TestNode extends GenericNode { /** * @param environment the environment */ - public TestNode(final Environment environment) { + public TestNode(final Environment environment) { super(environment); } + @SuppressWarnings("unchecked") @Override - protected Object createT() { - return new Object(); + protected T createT() { + return (T) new Object(); } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt index c32ef8799f..de06bc3955 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/properties/TestNodeProperty.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -10,7 +10,6 @@ package it.unibo.alchemist.boundary.properties import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.NodeProperty import it.unibo.alchemist.model.Position @@ -18,14 +17,12 @@ import it.unibo.alchemist.model.properties.AbstractNodeProperty import org.apache.commons.math3.random.RandomGenerator class TestNodeProperty>( - val incarnation: Incarnation, val rng: RandomGenerator, val environment: Environment, node: Node, val s: String, ) : AbstractNodeProperty(node) { override fun cloneOnNewNode(node: Node): NodeProperty = TestNodeProperty( - incarnation, rng, environment, node, diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index c0058530c2..a065dda2ed 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -11,10 +11,7 @@ package it.unibo.alchemist.dsl import another.location.SimpleMonitor import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.PROTELIS -import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.SAPERE import it.unibo.alchemist.boundary.exporters.CSVExporter import it.unibo.alchemist.boundary.exportfilters.CommonFilters import it.unibo.alchemist.boundary.extractors.Time @@ -24,7 +21,6 @@ import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution import it.unibo.alchemist.model.GeoPosition -import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.actions.BrownianMove import it.unibo.alchemist.model.deployments.Circle @@ -40,10 +36,14 @@ import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.maps.actions.ReproduceGPSTrace import it.unibo.alchemist.model.maps.deployments.FromGPSTrace import it.unibo.alchemist.model.maps.environments.OSMEnvironment +import it.unibo.alchemist.model.maps.environments.oSMEnvironment import it.unibo.alchemist.model.nodes.testNode import it.unibo.alchemist.model.positionfilters.Rectangle import it.unibo.alchemist.model.positions.Euclidean2DPosition +import it.unibo.alchemist.model.protelis.ProtelisIncarnation import it.unibo.alchemist.model.reactions.Event +import it.unibo.alchemist.model.sapere.ILsaMolecule +import it.unibo.alchemist.model.sapere.SAPEREIncarnation import it.unibo.alchemist.model.terminators.AfterTime import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.timedistributions.DiracComb @@ -55,7 +55,7 @@ import org.apache.commons.math3.random.MersenneTwister object DslLoaderFunctions { fun > test01Nodes(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(5.0) deployments { @@ -66,7 +66,7 @@ object DslLoaderFunctions { } fun > test02ManyNodes(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() return simulation(incarnation) { simulationGenerator = MersenneTwister(10L) scenarioGenerator = MersenneTwister(20L) @@ -86,7 +86,7 @@ object DslLoaderFunctions { } } fun > test03Grid(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { @@ -105,7 +105,7 @@ object DslLoaderFunctions { } } fun > test05Content(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { @@ -130,7 +130,7 @@ object DslLoaderFunctions { } } fun > test06ContentFiltered(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { @@ -157,7 +157,7 @@ object DslLoaderFunctions { } fun > test07Programs(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { @@ -190,34 +190,31 @@ object DslLoaderFunctions { } } } - fun > test08ProtelisPrograms(): Loader { - val incarnation = PROTELIS.incarnation() - return simulation(incarnation) { - deployments { - deploy(point(1.5, 0.5)) { - programs { - all { - timeDistribution = +JaktaTimeDistribution( - sense = WeibullTime( - 1.0, - 1.0, - ctx.ctx.ctx.generator, - ), - deliberate = DiracComb(0.1), - act = ExponentialTime( - 1.0, - ctx.ctx.ctx.generator, - ), - ) - program = "1 + 1" - } + fun > test08ProtelisPrograms(): Loader = simulation(ProtelisIncarnation()) { + deployments { + deploy(point(1.5, 0.5)) { + programs { + all { + timeDistribution = +JaktaTimeDistribution( + sense = WeibullTime( + 1.0, + 1.0, + ctx.ctx.ctx.generator, + ), + deliberate = DiracComb(0.1), + act = ExponentialTime( + 1.0, + ctx.ctx.ctx.generator, + ), + ) + program = "1 + 1" } } } } } fun > test09TimeDistribution(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { @@ -243,8 +240,8 @@ object DslLoaderFunctions { } } } - fun > test10Environment(): Loader { - val incarnation = SAPERE.incarnation() + fun test10Environment(): Loader { + val incarnation = SAPEREIncarnation() val env = OSMEnvironment(incarnation, "vcm.pbf", false) return simulation(incarnation, { env }) { terminators { @@ -278,24 +275,34 @@ object DslLoaderFunctions { } } } - fun > test11monitors(): Loader { - val incarnation = SAPERE.incarnation() + fun test11monitors(): Loader { + val incarnation = SAPEREIncarnation() return simulation(incarnation) { monitors { - +SimpleMonitor() + +SimpleMonitor, Euclidean2DPosition>() } } } - fun > test12Layers(): Loader { - val incarnation = SAPERE.incarnation() + fun test12Layers(): Loader { + val incarnation = SAPEREIncarnation() return simulation(incarnation) { layer { molecule = "A" - layer = StepLayer(2.0, 2.0, 100.0, 0.0) + layer = StepLayer( + 2.0, + 2.0, + incarnation.createConcentration("100"), + incarnation.createConcentration("0"), + ) } layer { molecule = "B" - layer = StepLayer(-2.0, -2.0, 0.0, 100.0) + layer = StepLayer( + -2.0, + -2.0, + incarnation.createConcentration("0"), + incarnation.createConcentration("100"), + ) } deployments { deploy( @@ -316,36 +323,30 @@ object DslLoaderFunctions { } } } - fun > test13GlobalReaction(): Loader { - val incarnation = PROTELIS.incarnation() - return simulation(incarnation) { - programs { - +globalTestReaction(DiracComb(1.0)) - } + fun test13GlobalReaction(): Loader = simulation(ProtelisIncarnation()) { + programs { + +globalTestReaction(DiracComb(1.0)) } } - fun > test14Exporters(): Loader { - val incarnation = PROTELIS.incarnation() - return simulation(incarnation) { - exporter { - type = CSVExporter( - "test_export_interval", - 4.0, - ) - data( - Time(), - moleculeReader( - "default_module:default_program", - null, - CommonFilters.NOFILTER.filteringPolicy, - emptyList(), - ), - ) - } + fun > test14Exporters(): Loader = simulation(ProtelisIncarnation()) { + exporter { + type = CSVExporter( + "test_export_interval", + 4.0, + ) + data( + Time(), + moleculeReader( + "default_module:default_program", + null, + CommonFilters.NOFILTER.filteringPolicy, + emptyList(), + ), + ) } } fun > test15Variables(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() return simulation(incarnation) { val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) @@ -386,7 +387,7 @@ object DslLoaderFunctions { } fun > test16ProgramsFilters(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { @@ -418,7 +419,7 @@ object DslLoaderFunctions { } } fun > test17CustomNodes(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() return simulation(incarnation) { deployments { deploy( @@ -430,14 +431,14 @@ object DslLoaderFunctions { ), ) { nodes { - testNode() as Node + testNode() } } } } } fun > test18NodeProperties(): Loader { - val incarnation = SAPERE.incarnation() + val incarnation = SAPEREIncarnation() val environment = Continuous2DEnvironment(incarnation) return simulation(incarnation, { environment }) { deployments { @@ -464,58 +465,56 @@ object DslLoaderFunctions { } } } - fun > test20Actions(): Loader { - val incarnation = SAPERE.incarnation() - val env = OSMEnvironment(incarnation) - return simulation(incarnation, { env }) { - networkModel = ConnectWithinDistance(1000.0) - deployments { - val lagoon = listOf( - Pair(45.2038121, 12.2504425), - Pair(45.2207426, 12.2641754), - Pair(45.2381516, 12.2806549), - Pair(45.2570053, 12.2895813), - Pair(45.276336, 12.2957611), - Pair(45.3029049, 12.2991943), - Pair(45.3212544, 12.3046875), - Pair(45.331875, 12.3040009), - Pair(45.3453893, 12.3040009), - Pair(45.3502151, 12.3156738), - Pair(45.3622776, 12.3232269), - Pair(45.3719259, 12.3300934), - Pair(45.3830193, 12.3348999), - Pair(45.395557, 12.3445129), - Pair(45.3998964, 12.3300934), - Pair(45.4018249, 12.3136139), - Pair(45.4105023, 12.3122406), - Pair(45.4167685, 12.311554), - Pair(45.4278531, 12.3012543), - Pair(45.4408627, 12.2902679), - Pair(45.4355628, 12.2772217), - Pair(45.4206242, 12.2703552), - Pair(45.3994143, 12.2744751), - Pair(45.3738553, 12.2676086), - Pair(45.3579354, 12.2614288), - Pair(45.3429763, 12.2497559), - Pair(45.3198059, 12.2408295), - Pair(45.2975921, 12.2346497), - Pair(45.2802014, 12.2408295), - Pair(45.257972, 12.233963), - Pair(45.2038121, 12.2504425), - ) - deploy(polygon(500, lagoon)) { - programs { - all { - timeDistribution("10") - reaction = Event(node, timeDistribution) - addAction { - BrownianMove( - env, - node, - ctx.ctx.ctx.ctx.simulationGenerator, - 0.0005, - ) - } + fun > test20Actions(): Loader = simulation(SAPEREIncarnation(), { + oSMEnvironment() + }) { + networkModel = ConnectWithinDistance(1000.0) + deployments { + val lagoon = listOf( + Pair(45.2038121, 12.2504425), + Pair(45.2207426, 12.2641754), + Pair(45.2381516, 12.2806549), + Pair(45.2570053, 12.2895813), + Pair(45.276336, 12.2957611), + Pair(45.3029049, 12.2991943), + Pair(45.3212544, 12.3046875), + Pair(45.331875, 12.3040009), + Pair(45.3453893, 12.3040009), + Pair(45.3502151, 12.3156738), + Pair(45.3622776, 12.3232269), + Pair(45.3719259, 12.3300934), + Pair(45.3830193, 12.3348999), + Pair(45.395557, 12.3445129), + Pair(45.3998964, 12.3300934), + Pair(45.4018249, 12.3136139), + Pair(45.4105023, 12.3122406), + Pair(45.4167685, 12.311554), + Pair(45.4278531, 12.3012543), + Pair(45.4408627, 12.2902679), + Pair(45.4355628, 12.2772217), + Pair(45.4206242, 12.2703552), + Pair(45.3994143, 12.2744751), + Pair(45.3738553, 12.2676086), + Pair(45.3579354, 12.2614288), + Pair(45.3429763, 12.2497559), + Pair(45.3198059, 12.2408295), + Pair(45.2975921, 12.2346497), + Pair(45.2802014, 12.2408295), + Pair(45.257972, 12.233963), + Pair(45.2038121, 12.2504425), + ) + deploy(polygon(500, lagoon)) { + programs { + all { + timeDistribution("10") + reaction = Event(node, timeDistribution) + addAction { + BrownianMove( + env, + node, + ctx.ctx.ctx.ctx.simulationGenerator, + 0.0005, + ) } } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt index 778d456138..f2fea3966a 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -9,24 +9,22 @@ package it.unibo.alchemist.dsl -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.SAPERE import it.unibo.alchemist.model.deployments.Point -import it.unibo.alchemist.model.positions.Euclidean2DPosition +import it.unibo.alchemist.model.sapere.SAPEREIncarnation +import it.unibo.alchemist.model.sapere.molecules.LsaMolecule import org.junit.jupiter.api.Test class TestContents { @Test fun testAll() { - val incarnation = SAPERE.incarnation() - val loader = simulation(incarnation) { + val loader = simulation(SAPEREIncarnation()) { deployments { deploy(Point(ctx.environment, 0.0, 0.0)) { all { molecule = "test" - concentration = 1.0 + concentration = listOf(LsaMolecule("1")) } } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index 98e932a20c..68dbb3971b 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -9,20 +9,17 @@ package it.unibo.alchemist.dsl -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point -import it.unibo.alchemist.model.positions.Euclidean2DPosition +import it.unibo.alchemist.model.sapere.SAPEREIncarnation import org.junit.jupiter.api.Test class TestDeployments { @Test fun testDeployments() { - val incarnation = AvailableIncarnations.SAPERE.incarnation() - val loader = simulation(incarnation) { + val loader = simulation(SAPEREIncarnation()) { deployments { val p = Point(ctx.environment, 0.0, 0.0) deploy(p) @@ -34,8 +31,7 @@ class TestDeployments { @Test fun testMultipleDeployments() { - val incarnation = AvailableIncarnations.SAPERE.incarnation() - val loader = simulation(incarnation) { + val loader = simulation(SAPEREIncarnation()) { deployments { val point = Point(ctx.environment, 0.0, 0.0) deploy(point) @@ -48,8 +44,7 @@ class TestDeployments { @Test fun testGridDeployment() { - val incarnation = AvailableIncarnations.SAPERE.incarnation() - val loader = simulation(incarnation) { + val loader = simulation(SAPEREIncarnation()) { deployments { val grid = Grid( ctx.environment, diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt index ed435d963c..820832dc8a 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt @@ -9,27 +9,22 @@ package it.unibo.alchemist.dsl -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.SAPERE import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance -import it.unibo.alchemist.model.positions.Euclidean2DPosition +import it.unibo.alchemist.model.sapere.SAPEREIncarnation import org.junit.jupiter.api.Test class TestSimulations { @Test fun testIncarnation() { - val incarnation = SAPERE.incarnation() - val loader = simulation(incarnation) { - } + val loader = simulation(SAPEREIncarnation()) { } loader.launch(loader.launcher) } @Test fun testLinkingRule() { - val incarnation = SAPERE.incarnation() - val loader = simulation(incarnation) { + val loader = simulation(SAPEREIncarnation()) { networkModel = ConnectWithinDistance(5.0) } loader.launch(loader.launcher) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt index a7fc78f1f9..132630ea42 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -13,51 +13,43 @@ import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.booleans.shouldBeTrue import io.kotest.matchers.doubles.shouldBeExactly import io.kotest.matchers.shouldBe -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.SAPERE -import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.positions.Euclidean2DPosition +import it.unibo.alchemist.model.sapere.SAPEREIncarnation +import it.unibo.alchemist.model.sapere.molecules.LsaMolecule import org.junit.jupiter.api.Test -@Suppress("UNCHECKED_CAST") + class TestVariables { @Test - fun > testDefaultValue() { - val incarnation = SAPERE.incarnation() - simulation(incarnation) { + fun

> testDefaultValue() { + simulation(SAPEREIncarnation()) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) runLater { println("Checking variable") rate.shouldBeExactly(5.0) - (this as SimulationContextImpl).variablesContext - .variables.containsKey("rate").shouldBeTrue() + this.variablesContext.variables.containsKey("rate").shouldBeTrue() } - }.getDefault() // needed to build the simulation + }.getDefault, P>() // needed to build the simulation } @Test - fun > testOverrideValue() { - val incarnation = SAPERE.incarnation() - val loader = simulation(incarnation) { + fun

> testOverrideValue() { + val loader = simulation(SAPEREIncarnation()) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) deployments { rate.shouldBeExactly(20.0) - (this@simulation as SimulationContextImpl).variablesContext - .variables.containsKey("rate").shouldBeTrue() + variablesContext.variables.containsKey("rate").shouldBeTrue() } } - loader.getWith(mapOf("rate" to 20.0)) + loader.getWith, P>(mapOf("rate" to 20.0)) } - @Suppress("NoNameShadowing") @Test - fun > testDoubleDeclaration() { - val incarnation = SAPERE.incarnation() - simulation(incarnation) { + fun

> testDoubleDeclaration() { + simulation(SAPEREIncarnation()) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) println("First declaration of rate: $rate") shouldThrow { @@ -68,9 +60,8 @@ class TestVariables { } @Test - fun > testDependendVariable() { - val incarnation = SAPERE.incarnation() - val loader = simulation(incarnation) { + fun

> testDependendVariable() { + val loader = simulation(SAPEREIncarnation()) { val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) @@ -86,6 +77,6 @@ class TestVariables { sourceSize.shouldBe(2.0) } } - loader.getWith(mapOf("size" to 10.0)) + loader.getWith, P>(mapOf("size" to 10.0)) } } diff --git a/alchemist-maps/build.gradle.kts b/alchemist-maps/build.gradle.kts index 0b45f11e5f..5a2eda69a0 100644 --- a/alchemist-maps/build.gradle.kts +++ b/alchemist-maps/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -15,6 +15,7 @@ plugins { } dependencies { + ksp(alchemist("dsl-processor")) api(alchemist("api")) implementation(alchemist("implementationbase")) diff --git a/alchemist-physics/build.gradle.kts b/alchemist-physics/build.gradle.kts index a2a01bad46..f988562eaf 100644 --- a/alchemist-physics/build.gradle.kts +++ b/alchemist-physics/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -14,6 +14,7 @@ plugins { } dependencies { + ksp(alchemist("dsl-processor")) api(alchemist("api")) api(alchemist("euclidean-geometry")) implementation(alchemist("implementationbase")) diff --git a/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/reactions/PhysicsUpdate.kt b/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/reactions/PhysicsUpdate.kt index d778ba8e08..8b4234b8e6 100644 --- a/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/reactions/PhysicsUpdate.kt +++ b/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/reactions/PhysicsUpdate.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -33,6 +33,7 @@ class PhysicsUpdate( val environment: Dynamics2DEnvironment, override val timeDistribution: TimeDistribution, ) : GlobalReaction { + constructor( environment: Dynamics2DEnvironment, updateRate: Double = 30.0, diff --git a/alchemist-physics/src/test/kotlin/it/unibo/alchemist/model/physics/environments/TestEuclideanPhysics2DEnvironment.kt b/alchemist-physics/src/test/kotlin/it/unibo/alchemist/model/physics/environments/TestEuclideanPhysics2DEnvironment.kt index c7f30784f9..f74d9f1a7d 100644 --- a/alchemist-physics/src/test/kotlin/it/unibo/alchemist/model/physics/environments/TestEuclideanPhysics2DEnvironment.kt +++ b/alchemist-physics/src/test/kotlin/it/unibo/alchemist/model/physics/environments/TestEuclideanPhysics2DEnvironment.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.physics.environments -import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Node.Companion.asProperty import it.unibo.alchemist.model.SupportedIncarnations @@ -32,13 +31,10 @@ class TestEuclideanPhysics2DEnvironment { private lateinit var node2: Node private lateinit var node3: Node - private fun createCircleNode( - incarnation: Incarnation, - environment: Physics2DEnvironment, - radius: Double, - ) = GenericNode(incarnation, environment).apply { - addProperty(CircularArea(environment, this, radius)) - } + private fun createCircleNode(environment: Physics2DEnvironment, radius: Double) = + GenericNode(environment).apply { + addProperty(CircularArea(environment, this, radius)) + } private fun getNodeRadius(node: Node): Double = node.asProperty>().shape.radius @@ -47,9 +43,9 @@ class TestEuclideanPhysics2DEnvironment { val incarnation = SupportedIncarnations.get("protelis").orElseThrow() environment = ContinuousPhysics2DEnvironment(incarnation) environment.linkingRule = NoLinks() - node1 = createCircleNode(incarnation, environment, DEFAULT_SHAPE_SIZE / 2) - node2 = createCircleNode(incarnation, environment, DEFAULT_SHAPE_SIZE / 2) - node3 = createCircleNode(incarnation, environment, DEFAULT_SHAPE_SIZE / 2) + node1 = createCircleNode(environment, DEFAULT_SHAPE_SIZE / 2) + node2 = createCircleNode(environment, DEFAULT_SHAPE_SIZE / 2) + node3 = createCircleNode(environment, DEFAULT_SHAPE_SIZE / 2) } @Test diff --git a/alchemist-smartcam/build.gradle.kts b/alchemist-smartcam/build.gradle.kts index 0f432bbdb9..ccebe83857 100644 --- a/alchemist-smartcam/build.gradle.kts +++ b/alchemist-smartcam/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -15,12 +15,11 @@ plugins { } dependencies { + ksp(alchemist("dsl-processor")) api(alchemist("api")) - implementation(alchemist("euclidean-geometry")) implementation(alchemist("implementationbase")) implementation(alchemist("physics")) - testImplementation(incarnation("protelis")) testImplementation(alchemist("loading")) } diff --git a/buildSrc/src/main/kotlin/dokka-convention.gradle.kts b/buildSrc/src/main/kotlin/dokka-convention.gradle.kts index 5aac25869d..d56b55c984 100644 --- a/buildSrc/src/main/kotlin/dokka-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/dokka-convention.gradle.kts @@ -1,4 +1,12 @@ -import gradle.kotlin.dsl.accessors._588bfaad08c3b59948e49854bb988ab1.versionCatalogs +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + import it.unibo.alchemist.build.ExternalDependency import it.unibo.alchemist.build.currentCommitHash import it.unibo.alchemist.build.registerExternal diff --git a/buildSrc/src/main/kotlin/kotlin-jvm-convention.gradle.kts b/buildSrc/src/main/kotlin/kotlin-jvm-convention.gradle.kts index 7f6a04b4f3..e8e3119f77 100644 --- a/buildSrc/src/main/kotlin/kotlin-jvm-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/kotlin-jvm-convention.gradle.kts @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2010-2025, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + import Libs.alchemist import it.unibo.alchemist.build.catalog @@ -14,6 +23,7 @@ plugins { id("dokka-convention") id("kotlin-static-analysis-convention") id("org.danilopianini.gradle-java-qa") + id("com.google.devtools.ksp") id("power-assert-convention") } From 15712fa5a7cacd6a3fa9868944c26a1a08081d00 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 2 Jan 2026 00:26:34 +0100 Subject: [PATCH 125/196] fixup!: continue refactoring the DSL --- .../boundary/dsl/model/ContentContext.kt | 24294 +--------------- .../boundary/dsl/model/DeploymentContext.kt | 4 +- .../boundary/dsl/model/DeploymentsContext.kt | 3 +- .../dsl/model/DeploymentsContextImpl.kt | 48 +- .../boundary/dsl/model/ProgramsContext.kt | 5 +- .../boundary/dsl/model/PropertiesContext.kt | 4 +- .../dsl/model/PropertiesContextImpl.kt | 6 +- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 7 +- 8 files changed, 44 insertions(+), 24327 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt index ea510e2a4d..c7e31af28f 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -38,24298 +38,6 @@ interface ContentContext> { * * The molecule is created using the incarnation's molecule factory. * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * * @see [it.unibo.alchemist.model.Incarnation.createMolecule] */ var molecule: String? diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt index 944ceea5e3..8a7b8681de 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -69,7 +69,7 @@ interface DeploymentContext> { * @see [PositionBasedFilter] * @see [ContentContext] */ - fun inside(filter: PositionBasedFilter<*>, block: ContentContext.() -> Unit) + fun inside(filter: PositionBasedFilter<*>, block: context(Node) ContentContext.() -> Unit) /** * Configures programs (reactions) for this deployment. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index 6daf6624d2..83978dc88e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -78,6 +78,7 @@ interface DeploymentsContext> { * @param block The configuration block for the deployment. * @see [it.unibo.alchemist.model.Deployment] */ + context(environment: Environment) fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt index e6c823cabe..0035d6bbb1 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -35,6 +35,7 @@ open class DeploymentsContextImpl>(override val ctx: Simulati private val inc = ctx.incarnation + context(environment: Environment) override fun deploy(deployment: Deployment<*>, block: context(DeploymentContext) () -> Unit) { logger.debug("Deploying deployment: {}", deployment) @Suppress("UNCHECKED_CAST") @@ -48,6 +49,7 @@ open class DeploymentsContextImpl>(override val ctx: Simulati @Suppress("UNCHECKED_CAST") this.deploy(deployment) {} } + context(_: Environment) private fun populateDeployment(deploymentContext: DeploymentContextImpl) { val deployment = deploymentContext.deployment // Additional linking rules @@ -69,27 +71,29 @@ open class DeploymentsContextImpl>(override val ctx: Simulati ctx.environment, null, ) - // load properties - deploymentContext.propertiesContext.applyToNode(node, position) - // load contents - val contents = deploymentContext.contents - for (content in contents) { - deploymentContext.applyToNodes(node, position, content) - } - // load programs - val programs = deploymentContext.programsContext.programs - val createdPrograms = mutableListOf?, Actionable>>() - for (programEntry in programs) { - val pp = deploymentContext.programsContext.applyToNodes( - node, - position, - programEntry.program, - programEntry.filter, - ) - createdPrograms.add(pp) + context(node) { + // load properties + deploymentContext.propertiesContext.applyToNode(node, position) + // load contents + val contents = deploymentContext.contents + for (content in contents) { + deploymentContext.applyToNodes(node, position, content) + } + // load programs + val programs = deploymentContext.programsContext.programs + val createdPrograms = mutableListOf?, Actionable>>() + for (programEntry in programs) { + val pp = deploymentContext.programsContext.applyToNodes( + node, + position, + programEntry.program, + programEntry.filter, + ) + createdPrograms.add(pp) + } + logger.debug("programs={}", createdPrograms) + logger.debug("Adding node to environment at position: {}", position) } - logger.debug("programs={}", createdPrograms) - logger.debug("Adding node to environment at position: {}", position) ctx.environment.addNode(node, position) } } @@ -134,7 +138,7 @@ open class DeploymentsContextImpl>(override val ctx: Simulati contents.add(c) } - override fun inside(filter: PositionBasedFilter<*>, block: ContentContext.() -> Unit) { + override fun inside(filter: PositionBasedFilter<*>, block: context(Node) ContentContext.() -> Unit) { @Suppress("UNCHECKED_CAST") val typedFilter = filter as PositionBasedFilter

logger.debug("Adding content for positions inside filter: {}", typedFilter) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt index ebd4dc072c..662c34fcc3 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -12,6 +12,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.dsl.AlchemistDsl import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Condition +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter @@ -61,7 +62,7 @@ interface ProgramsContext> { * * @param block The program configuration block. */ - fun all(block: ProgramContext.() -> Unit) + fun all(block: context(Environment, Node) ProgramContext.() -> Unit) /** * Configures a program for nodes inside a position filter. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt index d5db4c3f69..8817ff430f 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt @@ -46,7 +46,8 @@ import it.unibo.alchemist.model.PositionBasedFilter * @see [NodeProperty] for the property interface * @see [PositionBasedFilter] for position filtering */ - +// TODO: remove when detekt false positive is fixed +@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters @AlchemistDsl interface PropertiesContext> { /** @@ -63,6 +64,7 @@ interface PropertiesContext> { * @param block The property configuration block. * @see [PositionBasedFilter] */ + context(environment: Environment) fun inside( filter: PositionBasedFilter

, block: context(Environment, Node) PropertyContext.() -> Unit, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt index f6d5c2c8c5..90ae8b5e5d 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt @@ -22,6 +22,8 @@ import it.unibo.alchemist.model.PositionBasedFilter * @param T The type of molecule concentration. * @param P The type of position. */ +// TODO: remove when detekt false positive is fixed +@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters class PropertiesContextImpl>(override val ctx: DeploymentContext) : PropertiesContext { /** * List of property contexts with their associated filters. @@ -34,6 +36,7 @@ class PropertiesContextImpl>(override val ctx: DeploymentCont >, > = mutableListOf() + context(_: Environment) override fun inside( filter: PositionBasedFilter

, block: context(Environment, Node) PropertyContext.() -> Unit, @@ -53,11 +56,12 @@ class PropertiesContextImpl>(override val ctx: DeploymentCont * @param node The node to apply properties to. * @param position The position of the node. */ + context(_: Environment, _: Node) fun applyToNode(node: Node, position: P) { propertiesCtx.forEach { (propertyCtx, filter) -> if (filter == null || filter.contains(position)) { val properties = PropertyContextImpl(filter, node) - .apply(propertyCtx) + .apply { propertyCtx() } .properties properties.forEach { property -> logger.debug("Applying property: {} to node: {}", property, node) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index a065dda2ed..d3d1caa682 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -22,7 +22,7 @@ import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.actions.BrownianMove +import it.unibo.alchemist.model.actions.brownianMove import it.unibo.alchemist.model.deployments.Circle import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point @@ -509,10 +509,7 @@ object DslLoaderFunctions { timeDistribution("10") reaction = Event(node, timeDistribution) addAction { - BrownianMove( - env, - node, - ctx.ctx.ctx.ctx.simulationGenerator, + brownianMove( 0.0005, ) } From 798255c599950d790abb67d6f21961842fbb4f54 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sat, 3 Jan 2026 17:47:48 +0100 Subject: [PATCH 126/196] chore: remove redundant type bound --- .../it/unibo/alchemist/boundary/loader/SimulationModel.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt index ebc7f045bf..f9471f6ab6 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -253,7 +253,7 @@ internal object SimulationModel { } } - internal fun

, T : Any?> visitIncarnation(root: Any?): Incarnation = + internal fun

, T> visitIncarnation(root: Any?): Incarnation = SupportedIncarnations.get(root.toString()).orElseThrow { IllegalArgumentException( "Invalid incarnation descriptor: $root. " + @@ -261,7 +261,7 @@ internal object SimulationModel { ) } - internal fun

, T : Any?> visitLinkingRule(localContext: Context, root: Any?): LinkingRule { + internal fun

, T> visitLinkingRule(localContext: Context, root: Any?): LinkingRule { val linkingRules = visitRecursively(localContext, root, JavaType) { element -> visitBuilding>(localContext, element) From cdde10acbaf5e1fd04bac835ebbcd806e6bf832f Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sat, 3 Jan 2026 19:23:43 +0100 Subject: [PATCH 127/196] refactor: update context parameters in DSL methods for consistency --- .../unibo/alchemist/boundary/dsl/DSLLoader.kt | 16 ++-- .../boundary/dsl/model/DeploymentContext.kt | 2 + .../boundary/dsl/model/DeploymentsContext.kt | 3 +- .../dsl/model/DeploymentsContextImpl.kt | 8 +- .../boundary/dsl/model/ExporterContext.kt | 2 +- .../boundary/dsl/model/ExporterContextImpl.kt | 2 +- .../boundary/dsl/model/ProgramsContext.kt | 8 +- .../boundary/dsl/model/ProgramsContextImpl.kt | 84 +++++++++++-------- .../dsl/model/SimulationContextImpl.kt | 8 +- 9 files changed, 82 insertions(+), 51 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt index d6981917f1..4746135e03 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -9,7 +9,6 @@ package it.unibo.alchemist.boundary.dsl -import it.unibo.alchemist.boundary.Exporter import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.dsl.model.SimulationContext import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl @@ -29,14 +28,15 @@ abstract class DSLLoader(private val ctx: SimulationContext<*, *>) : Loader { protected abstract fun > envFactory(): Environment + @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation = - SingleUseLoader(ctx).load(values) - private inner class SingleUseLoader(private val ctx: SimulationContext<*, *>) { + SingleUseLoader(ctx as SimulationContext).load(values) + + private inner class SingleUseLoader>(private val ctx: SimulationContext) { private val mutex = Semaphore(1) private var consumed = false - @Suppress("UNCHECKED_CAST") - fun > load(values: Map): Simulation { + fun load(values: Map): Simulation { try { mutex.acquireUninterruptibly() check(!consumed) { "This loader has already been consumed! This is a bug in Alchemist" } @@ -67,9 +67,9 @@ abstract class DSLLoader(private val ctx: SimulationContext<*, *>) : Loader { // EXPORTERS val exporters = simulationIstance.exporters.map { it.type.apply { - it.type?.bindDataExtractors(it.extractors) + bindDataExtractors(it.extractors) } - } as List> + } exporters.forEach { it.bindVariables(ctx.variablesContext.references.get()) } if (exporters.isNotEmpty()) { engine.addOutputMonitor(GlobalExporter(exporters)) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt index 8a7b8681de..d5d39bf8a4 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt @@ -51,6 +51,7 @@ interface DeploymentContext> { * @param block The content configuration block. * @see [ContentContext] */ + context(_: Node) fun all(block: ContentContext.() -> Unit) /** @@ -69,6 +70,7 @@ interface DeploymentContext> { * @see [PositionBasedFilter] * @see [ContentContext] */ + context(_: Node) fun inside(filter: PositionBasedFilter<*>, block: context(Node) ContentContext.() -> Unit) /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index 83978dc88e..10cc6e257e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -11,6 +11,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import org.apache.commons.math3.random.RandomGenerator @@ -79,7 +80,7 @@ interface DeploymentsContext> { * @see [it.unibo.alchemist.model.Deployment] */ context(environment: Environment) - fun deploy(deployment: Deployment<*>, block: DeploymentContext.() -> Unit) + fun deploy(deployment: Deployment<*>, block: context(Node) DeploymentContext.() -> Unit) /** * Deploys nodes using a deployment without additional configuration. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt index 0035d6bbb1..8f6c4b7a67 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt @@ -36,10 +36,10 @@ open class DeploymentsContextImpl>(override val ctx: Simulati private val inc = ctx.incarnation context(environment: Environment) - override fun deploy(deployment: Deployment<*>, block: context(DeploymentContext) () -> Unit) { + override fun deploy(deployment: Deployment<*>, block: context(Node) DeploymentContext.() -> Unit) { logger.debug("Deploying deployment: {}", deployment) @Suppress("UNCHECKED_CAST") - val d = DeploymentContextImpl(deployment as Deployment

).apply(block) + val d = DeploymentContextImpl(deployment as Deployment

).apply { block() } // populate populateDeployment(d) } @@ -132,17 +132,19 @@ open class DeploymentsContextImpl>(override val ctx: Simulati logger.debug("Visiting deployment: {}", deployment) } + context(_: Node) override fun all(block: ContentContext.() -> Unit) { logger.debug("Adding content for all positions") val c = ContentContextImpl().apply(block) contents.add(c) } + context(_: Node) override fun inside(filter: PositionBasedFilter<*>, block: context(Node) ContentContext.() -> Unit) { @Suppress("UNCHECKED_CAST") val typedFilter = filter as PositionBasedFilter

logger.debug("Adding content for positions inside filter: {}", typedFilter) - val c = ContentContextImpl(typedFilter).apply(block) + val c = ContentContextImpl(typedFilter).apply { block() } contents.add(c) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt index 68e67625c7..11c8e1a1d4 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt @@ -49,7 +49,7 @@ interface ExporterContext> { * * @see [Exporter] */ - var type: Exporter? + var type: Exporter /** * Sets the data extractors for this exporter. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt index 45d3a2c853..075d3bd37f 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt @@ -20,7 +20,7 @@ import it.unibo.alchemist.model.Position * @param P The type of position. */ class ExporterContextImpl>(override val ctx: SimulationContext) : ExporterContext { - override var type: Exporter? = null + override lateinit var type: Exporter /** * The list of data extractors. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt index 662c34fcc3..4bab9e942b 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt @@ -51,6 +51,8 @@ import it.unibo.alchemist.model.TimeDistribution * @see [TimeDistribution] for time distribution configuration */ @AlchemistDsl +// TODO: remove when detekt false positive is fixed +@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters interface ProgramsContext> { /** * The deployment context this programs context belongs to. @@ -62,6 +64,7 @@ interface ProgramsContext> { * * @param block The program configuration block. */ + context(_: Environment, _: Node) fun all(block: context(Environment, Node) ProgramContext.() -> Unit) /** @@ -73,7 +76,10 @@ interface ProgramsContext> { * @param block The program configuration block. * @see [PositionBasedFilter] */ - fun inside(filter: PositionBasedFilter

, block: ProgramContext.() -> Unit) + fun inside( + filter: PositionBasedFilter

, + block: context(Environment, Node) ProgramContext.() -> Unit, + ) } /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt index 917467ddd4..06cb0c1a30 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt @@ -1,9 +1,19 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Condition +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter @@ -17,6 +27,8 @@ import it.unibo.alchemist.model.TimeDistribution * @param P The type of position. * @param ctx The deployments context. */ +// TODO: remove when detekt false positive is fixed +@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters class ProgramsContextImpl>(override val ctx: DeploymentContext) : ProgramsContext { /** * Entry representing a program with its filter. @@ -26,7 +38,7 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex */ inner class ProgramEntry( val filter: PositionBasedFilter

?, - val program: ProgramsContextImpl.ProgramContextImpl.() -> Unit, + val program: context(Environment, Node) ProgramsContextImpl.ProgramContextImpl.() -> Unit, ) /** @@ -34,12 +46,16 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex */ val programs: MutableList = mutableListOf() - override fun all(block: ProgramContext.() -> Unit) { + context(_: Environment, _: Node) + override fun all(block: context(Environment, Node) ProgramContext.() -> Unit) { logger.debug("Adding program for all nodes") programs.add(ProgramEntry(null, block)) } - override fun inside(filter: PositionBasedFilter

, block: ProgramContext.() -> Unit) { + override fun inside( + filter: PositionBasedFilter

, + block: context(Environment, Node) ProgramContext.() -> Unit, + ) { logger.debug("Adding program for nodes inside filter: {}", filter) programs.add(ProgramEntry(filter, block)) } @@ -55,39 +71,41 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex fun applyToNodes( node: Node, position: P, - program: ProgramContextImpl.() -> Unit, + program: context(Environment, Node) ProgramContextImpl.() -> Unit, filter: PositionBasedFilter

?, ): Pair?, Actionable> { - logger.debug("Applying program to node at position: {}", position) - val c = ProgramContextImpl(node).apply(program) - val context = ctx.ctx.ctx - logger.debug("Creating time distribution for program") - val timeDistribution = c.timeDistribution - ?: context.incarnation.createTimeDistribution( - context.simulationGenerator, - context.environment, - node, - null, - ) - logger.debug("Creating reaction for program") - val r = c.reaction - ?: // Create a basic reaction with custom actions/conditions - context.incarnation.createReaction( - context.simulationGenerator, - context.environment, - node, - timeDistribution, - c.program, - ) - logger.debug("Adding actions to reaction") - r.actions += c.actions.map { it() } - logger.debug("Adding conditions to reaction") - r.conditions += c.conditions.map { it() } - logger.debug("Adding reaction to node") - if (filter == null || filter.contains(position)) { - node.addReaction(r) + context(ctx.ctx.ctx.environment, node) { + logger.debug("Applying program to node at position: {}", position) + val c = ProgramContextImpl(node).apply { program() } + val context = ctx.ctx.ctx + logger.debug("Creating time distribution for program") + val timeDistribution = c.timeDistribution + ?: context.incarnation.createTimeDistribution( + context.simulationGenerator, + context.environment, + node, + null, + ) + logger.debug("Creating reaction for program") + val r = c.reaction + ?: // Create a basic reaction with custom actions/conditions + context.incarnation.createReaction( + context.simulationGenerator, + context.environment, + node, + timeDistribution, + c.program, + ) + logger.debug("Adding actions to reaction") + r.actions += c.actions.map { it() } + logger.debug("Adding conditions to reaction") + r.conditions += c.conditions.map { it() } + logger.debug("Adding reaction to node") + if (filter == null || filter.contains(position)) { + node.addReaction(r) + } + return filter to r } - return filter to r } /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt index 92d8162b3a..6c92bf4720 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -50,10 +50,12 @@ class SimulationContextImpl>( */ val monitors: MutableList> = mutableListOf() + private val _exporters: MutableList> = mutableListOf() + /** * List of exporters. */ - val exporters: MutableList> = mutableListOf() + val exporters: List> get() = _exporters override var launcher: Launcher = DefaultLauncher() @@ -131,7 +133,7 @@ class SimulationContextImpl>( } override fun exporter(block: ExporterContext.() -> Unit) { - buildSteps.add { this.exporters.add(ExporterContextImpl(this).apply(block)) } + buildSteps.add { this._exporters.add(ExporterContextImpl(this).apply(block)) } } override fun programs(block: GlobalProgramsContext.() -> Unit) { From b8efa8bf9325f466b9d886579c91dc8273c551fc Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 5 Jan 2026 01:03:22 +0100 Subject: [PATCH 128/196] refactor: update deployment context methods for improved node factory handling --- .../boundary/dsl/model/DeploymentContext.kt | 18 ------- .../boundary/dsl/model/DeploymentsContext.kt | 26 +++++----- .../dsl/model/DeploymentsContextImpl.kt | 47 ++++--------------- .../unibo/alchemist/model/deployments/Grid.kt | 10 ++-- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 4 +- .../alchemist/dsl/SimulationsComparisons.kt | 10 ++-- .../it/unibo/alchemist/dsl/TestDeployments.kt | 2 +- 7 files changed, 34 insertions(+), 83 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt index d5d39bf8a4..f72f54de3a 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.boundary.dsl.model -import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter @@ -91,23 +90,6 @@ interface DeploymentContext> { */ fun programs(block: ProgramsContext.() -> Unit) - /** - * Sets a custom node factory for this deployment. - * - * By default, nodes are created using the incarnation's node factory. - * This allows using custom node types. - * - * ```kotlin - * nodes { MyCustomNode() } - * ``` - * - * @param factory The factory function for creating nodes. - * @see [Node] - * @see [it.unibo.alchemist.model.Incarnation.createNode] - */ - context(environment: Environment) - fun nodes(factory: (DeploymentContext) -> Node) - /** * Configures properties for this deployment. * diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index 10cc6e257e..13e51818e4 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -79,17 +79,17 @@ interface DeploymentsContext> { * @param block The configuration block for the deployment. * @see [it.unibo.alchemist.model.Deployment] */ - context(environment: Environment) - fun deploy(deployment: Deployment<*>, block: context(Node) DeploymentContext.() -> Unit) - - /** - * Deploys nodes using a deployment without additional configuration. - * - * Nodes are created at the positions defined by the deployment with default settings. - * - * @param deployment The deployment that defines node positions. - * @see [Deployment] - */ - context(environment: Environment) - fun deploy(deployment: Deployment<*>) + // TODO: fix the doc + context(randomGenerator: RandomGenerator, environment: Environment) + fun deploy( + deployment: Deployment

, + nodeFactory: context(RandomGenerator, Environment) () -> Node = { + contextOf>().incarnation.createNode( + contextOf(), + contextOf>(), + null, + ) + }, + block: context(Environment, Node) DeploymentContext.() -> Unit = { }, + ) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt index 8f6c4b7a67..6ae77fc7cf 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt @@ -33,25 +33,13 @@ open class DeploymentsContextImpl>(override val ctx: Simulati override val generator: RandomGenerator get() = ctx.scenarioGenerator - private val inc = ctx.incarnation - - context(environment: Environment) - override fun deploy(deployment: Deployment<*>, block: context(Node) DeploymentContext.() -> Unit) { + context(randomGenerator: RandomGenerator, environment: Environment) + override fun deploy( + deployment: Deployment

, + nodeFactory: context(RandomGenerator, Environment) () -> Node, + block: context(Environment, Node) DeploymentContext.() -> Unit, + ) { logger.debug("Deploying deployment: {}", deployment) - @Suppress("UNCHECKED_CAST") - val d = DeploymentContextImpl(deployment as Deployment

).apply { block() } - // populate - populateDeployment(d) - } - - context(environment: Environment) - override fun deploy(deployment: Deployment<*>) { - @Suppress("UNCHECKED_CAST") - this.deploy(deployment) {} - } - context(_: Environment) - private fun populateDeployment(deploymentContext: DeploymentContextImpl) { - val deployment = deploymentContext.deployment // Additional linking rules deployment.getAssociatedLinkingRule()?.let { newLinkingRule -> val composedLinkingRule = @@ -62,17 +50,13 @@ open class DeploymentsContextImpl>(override val ctx: Simulati } ctx.environment.linkingRule = composedLinkingRule } - deployment.stream().forEach { position -> + deployment.forEach { position -> logger.debug("visiting position: {} for deployment: {}", position, deployment) logger.debug("creaing node for deployment: {}", deployment) - val node = deploymentContext.nodeFactory?.invoke(deploymentContext) - ?: inc.createNode( - ctx.simulationGenerator, // Match YAML loader: uses simulationRNG for node creation - ctx.environment, - null, - ) + val node = nodeFactory() context(node) { // load properties + val deploymentContext = DeploymentContextImpl(deployment).apply { block() } deploymentContext.propertiesContext.applyToNode(node, position) // load contents val contents = deploymentContext.contents @@ -111,14 +95,6 @@ open class DeploymentsContextImpl>(override val ctx: Simulati */ val contents: MutableList = mutableListOf() - /** - * Optional factory for creating custom nodes. - */ - var nodeFactory: ( - context(DeploymentContext) - () -> Node - )? = null - /** * The properties context for this deployment. */ @@ -152,11 +128,6 @@ open class DeploymentsContextImpl>(override val ctx: Simulati programsContext.apply(block) } - context(environment: Environment) - override fun nodes(factory: DeploymentContext.() -> Node) { - nodeFactory = factory - } - override fun properties(block: PropertiesContext.() -> Unit) { propertiesContext.apply(block) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt index 91d216cb76..a5b72a3feb 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/deployments/Grid.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -45,10 +45,10 @@ import org.apache.commons.math3.random.RandomGenerator * @param yShift * how shifted should be positions along columns */ -open class Grid +open class Grid

> @JvmOverloads constructor( - private val environment: Environment<*, *>, + private val environment: Environment<*, P>, private val randomGenerator: RandomGenerator, private val xStart: Double, private val yStart: Double, @@ -60,8 +60,8 @@ constructor( private val yRand: Double = 0.0, private val xShift: Double = 0.0, private val yShift: Double = 0.0, -) : Deployment> { - override fun stream(): Stream> { +) : Deployment

{ + override fun stream(): Stream

{ val positions = (0 until stepCount(yStart, yEnd, yStep)) .map { yn -> diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index d3d1caa682..5d2cde4f50 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -429,10 +429,8 @@ object DslLoaderFunctions { 0.0, 5.0, ), + nodeFactory = { testNode() }, ) { - nodes { - testNode() - } } } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt index 52b709b43b..661b80a173 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -55,22 +55,22 @@ class SimulationsComparisons { @Test fun > test10() { - { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/yml/10-environment.yml") + { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/yml/10-environment.yml") } @Test fun > test11() { - { DslLoaderFunctions.test11monitors() }.shouldEqual("dsl/yml/11-monitors.yml") + { DslLoaderFunctions.test11monitors() }.shouldEqual("dsl/yml/11-monitors.yml") } @Test fun > test12() { - { DslLoaderFunctions.test12Layers() }.shouldEqual("dsl/yml/12-layers.yml") + { DslLoaderFunctions.test12Layers() }.shouldEqual("dsl/yml/12-layers.yml") } @Test fun > test13() { - { DslLoaderFunctions.test13GlobalReaction() }.shouldEqual("dsl/yml/13-globalreaction.yml") + { DslLoaderFunctions.test13GlobalReaction() }.shouldEqual("dsl/yml/13-globalreaction.yml") } @Test diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index 68dbb3971b..ee91409381 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the From 045103947d2e3f30699a59041d0460e96b3d66da Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 23 Jan 2026 00:09:33 +0100 Subject: [PATCH 129/196] fix: most of the DSL works --- .../model/positionfilters/Rectangle.java | 40 ------------------- .../model/positionfilters/Rectangle.kt | 31 ++++++++++++++ .../unibo/alchemist/model/nodes/TestNode.java | 2 + .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 5 +-- .../it/unibo/alchemist/dsl/TestVariables.kt | 1 + 5 files changed, 36 insertions(+), 43 deletions(-) delete mode 100644 alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/positionfilters/Rectangle.kt diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java deleted file mode 100644 index 96685b2726..0000000000 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/positionfilters/Rectangle.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2010-2023, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.model.positionfilters; - -import it.unibo.alchemist.model.Position2D; - -import java.awt.geom.Rectangle2D; - -import static java.lang.Math.abs; -import static java.lang.Math.min; - -/** - * A Rectangle. - * - * @param

position type - */ -public class Rectangle

> extends Abstract2DShape

{ - - /** - * @param x - * start x point - * @param y - * start y point - * @param w - * width - * @param h - * height - */ - public Rectangle(final double x, final double y, final double w, final double h) { - super(new Rectangle2D.Double(min(x, x + w), min(y, y + h), abs(w), abs(h))); - } - -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/positionfilters/Rectangle.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/positionfilters/Rectangle.kt new file mode 100644 index 0000000000..4dc28d6a8e --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/model/positionfilters/Rectangle.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.model.positionfilters + +import it.unibo.alchemist.model.Position2D +import java.awt.geom.Rectangle2D +import kotlin.math.abs +import kotlin.math.min + +/** + * A Rectangle. + * + * @param x + * start x point + * @param y + * start y point + * @param w + * width + * @param h + * height + * @param

position type +

*/ +class Rectangle

>(x: Double, y: Double, w: Double, h: Double) : + Abstract2DShape

(Rectangle2D.Double(min(x, x + w), min(y, y + h), abs(w), abs(h))) diff --git a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java index b7c1fdaaa4..6fafd311a6 100644 --- a/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java +++ b/alchemist-loading/src/test/java/it/unibo/alchemist/model/nodes/TestNode.java @@ -15,6 +15,8 @@ /** * Generic node for testing purposes. + * + * @param concentration type */ public final class TestNode extends GenericNode { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 5d2cde4f50..c1fd0d59f8 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -449,13 +449,12 @@ object DslLoaderFunctions { ), ) { properties { - val filter = Rectangle(-3.0, -3.0, 2.0, 2.0) + val filter = Rectangle(-3.0, -3.0, 2.0, 2.0) // same - val filter2 = Rectangle(3.0, 3.0, 2.0, 2.0) inside(filter) { +testNodeProperty("a") } - inside(filter2) { + inside(Rectangle(3.0, 3.0, 2.0, 2.0)) { +testNodeProperty("b") } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt index 132630ea42..d8d199ab8f 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -48,6 +48,7 @@ class TestVariables { } @Test + @Suppress("NoNameShadowing") fun

> testDoubleDeclaration() { simulation(SAPEREIncarnation()) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) From 968c391553b56cc832a09523b34b564fff1382dc Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 23 Jan 2026 13:05:49 +0100 Subject: [PATCH 130/196] fix(loading): provide an environment factory when instancing the simulation --- .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 26 +++++++------------ .../dsl/model/SimulationContextImpl.kt | 14 +++++----- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index e617698bd7..056a683c04 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -62,27 +62,28 @@ object Dsl { * Creates a simulation with a custom environment. * * @param incarnation The incarnation instance. - * @param environment The environment instance. + * @param environmentFactory The environment instance. * @param block The simulation configuration block. * @return A loader instance. */ fun > simulation( incarnation: Incarnation, - environment: context(Incarnation) () -> Environment, + environmentFactory: context(Incarnation) () -> Environment, block: context( + Incarnation, RandomGenerator, - Environment + Environment, ) SimulationContext.() -> Unit, ): Loader { - val ctx = SimulationContextImpl(incarnation) + val ctx = SimulationContextImpl(incarnation, environmentFactory) ctx.apply { - context(ctx.simulationGenerator, ctx.environment) { + context(incarnation, ctx.simulationGenerator, ctx.environment) { block() } } return createLoader(ctx) { context(incarnation) { - environment() + environmentFactory() } } } @@ -99,16 +100,7 @@ object Dsl { block: context( Incarnation, RandomGenerator, - Environment + Environment, ) SimulationContext.() -> Unit, - ): Loader { - val defaultEnv = { Continuous2DEnvironment(incarnation) } - val ctx = SimulationContextImpl(incarnation) - ctx.apply { - context(incarnation, ctx.simulationGenerator, ctx.environment) { - block() - } - } - return createLoader(ctx, defaultEnv) - } + ): Loader = simulation(incarnation, { Continuous2DEnvironment(incarnation) }, block) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt index 6c92bf4720..8d4ec69375 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -7,8 +7,6 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -@file:Suppress("UNCHECKED_CAST") - package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.Launcher @@ -34,11 +32,14 @@ import org.apache.commons.math3.random.RandomGenerator class SimulationContextImpl>( override val incarnation: Incarnation, - private var envIstance: Environment? = null, + private val environmentFactory: context(Incarnation) () -> Environment, ) : SimulationContext { /** The environment instance (internal use). */ - override val environment: Environment - get() = requireNotNull(envIstance) { "Environment has not been initialized yet" } + override val environment: Environment by lazy { + context(incarnation) { + environmentFactory() + } + } /** * List of build steps to execute. @@ -104,8 +105,7 @@ class SimulationContextImpl>( * @see [VariablesContext] */ fun build(envInstance: Environment, values: Map): SimulationContextImpl { - val batchContext = SimulationContextImpl(incarnation) - batchContext.envIstance = envInstance + val batchContext = SimulationContextImpl(incarnation) { envInstance } batchContext.variablesContext.variables += this.variablesContext.variables batchContext.variablesContext.dependentVariables += this.variablesContext.dependentVariables logger.debug("Binding variables to batchInstance: {}", values) From d1c806dc1a8dca31fb6d6816ecadd31f7c7b44bb Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 23 Jan 2026 13:11:32 +0100 Subject: [PATCH 131/196] fix(loading): fix simple test --- .../kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt index 2e4dd85a15..2b886c5c80 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt @@ -18,10 +18,10 @@ import org.junit.jupiter.api.Test class KotlinDslProviderTest { @Test - fun loadSimpleScript() { + fun `a simple textual Kotlin DSL script should load`() { val script = """ - val inc = SAPERE.incarnation() - simulation(inc) { + import it.unibo.alchemist.model.sapere.SAPEREIncarnation + simulation(SAPEREIncarnation()) { networkModel = ConnectWithinDistance(5.0) deployments { deploy(point(0.0, 0.0)) From 3d1c4c20fd327bb6d7de419b327a053a65d26eb2 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 23 Jan 2026 13:15:00 +0100 Subject: [PATCH 132/196] chore: explain why an unused private member warning is suppressed --- .../it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt index d3bd9c4bf8..6673a839b7 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt @@ -83,6 +83,7 @@ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ compilerOptions.append("-Xcontext-parameters") } }) { + // See: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/input.html @Suppress("UnusedPrivateMember") private fun readResolve(): Any = AlchemistCompilationConfiguration } From fdcbc09ed53e05c3c9ac5303cd6394681bb27afb Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 23 Jan 2026 13:17:32 +0100 Subject: [PATCH 133/196] chore: sort imports --- .../boundary/dsl/scripting/AlchemistScript.kt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt index 6673a839b7..7395db65fc 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt @@ -41,25 +41,26 @@ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ "it.unibo.alchemist.boundary.dsl.generated.*", "it.unibo.alchemist.boundary.dsl.*", "it.unibo.alchemist.boundary.dsl.Dsl.*", - "it.unibo.alchemist.model.maps.actions.*", - "it.unibo.alchemist.model.maps.deployments.*", - "it.unibo.alchemist.model.maps.environments.*", "it.unibo.alchemist.model.*", - "it.unibo.alchemist.model.positions.*", "it.unibo.alchemist.model.deployments.*", - "it.unibo.alchemist.model.positionfilters.And", - "it.unibo.alchemist.model.positionfilters.Or", - "it.unibo.alchemist.model.positionfilters.Not", - "it.unibo.alchemist.model.positionfilters.Xor", + "it.unibo.alchemist.model.incarnations.*", "it.unibo.alchemist.model.actions.*", "it.unibo.alchemist.model.conditions.*", "it.unibo.alchemist.model.environments.*", "it.unibo.alchemist.model.geometry.*", "it.unibo.alchemist.model.layers.*", "it.unibo.alchemist.model.linkingrules.*", + "it.unibo.alchemist.model.maps.actions.*", + "it.unibo.alchemist.model.maps.deployments.*", + "it.unibo.alchemist.model.maps.environments.*", "it.unibo.alchemist.model.movestrategies.*", "it.unibo.alchemist.model.neighborhoods.*", "it.unibo.alchemist.model.nodes.*", + "it.unibo.alchemist.model.positions.*", + "it.unibo.alchemist.model.positionfilters.And", + "it.unibo.alchemist.model.positionfilters.Or", + "it.unibo.alchemist.model.positionfilters.Not", + "it.unibo.alchemist.model.positionfilters.Xor", "it.unibo.alchemist.model.properties.*", "it.unibo.alchemist.model.routes.*", "it.unibo.alchemist.model.reactions.*", From c0838b3722e707ac6653374317834ef9ca779652 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 23 Jan 2026 14:49:34 +0100 Subject: [PATCH 134/196] refactor: another gigantic refactor, holy shit --- .idea/codeStyles/Project.xml | 1 - alchemist-cognitive-agents/build.gradle.kts | 2 +- alchemist-euclidean-geometry/build.gradle.kts | 2 +- .../build.gradle.kts | 0 .../dsl/processor/DslBuilderProcessor.kt | 0 .../processor/DslBuilderProcessorProvider.kt | 0 .../datatypes/InjectableConstructor.kt | 0 .../dsl/processor/datatypes/TypePosition.kt | 0 .../extensions/KSDeclarationExtensions.kt | 0 .../KSFunctionDeclarationExtensions.kt | 0 .../extensions/KSTypeArgumentExtensions.kt | 0 .../processor/extensions/KSTypeExtensions.kt | 0 .../extensions/KSTypeReferenceExtensions.kt | 0 .../extensions/KSValueParameterExtensions.kt | 0 .../processor/extensions/ListExtensions.kt | 0 ...ols.ksp.processing.SymbolProcessorProvider | 0 alchemist-implementationbase/build.gradle.kts | 2 +- .../build.gradle.kts | 2 +- .../build.gradle.kts | 2 +- .../protelis/properties/ProtelisDevice.kt | 2 +- alchemist-incarnation-sapere/build.gradle.kts | 2 +- .../SAPEREIncarnation.java | 4 +- .../{ => incarnations}/ScafiIncarnation.scala | 8 +-- .../actions/RunScafiProgram.scala | 5 +- .../actions/SendScafiMessage.scala | 6 +- .../ScafiComputationalRoundComplete.scala | 8 +-- .../nodes/NodeManager.scala | 5 +- .../properties}/ScafiDevice.scala | 7 ++- alchemist-loading/build.gradle.kts | 23 +++---- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 39 ++++++------ .../alchemist/dsl/KotlinDslProviderTest.kt | 3 +- .../alchemist/dsl/SimulationsComparisons.kt | 60 +++++++++---------- .../it/unibo/alchemist/dsl/TestContents.kt | 2 +- .../it/unibo/alchemist/dsl/TestDeployments.kt | 2 +- .../it/unibo/alchemist/dsl/TestSimulations.kt | 2 +- .../it/unibo/alchemist/dsl/TestVariables.kt | 2 +- .../dsl/kts/11-monitors.alchemist.kts | 18 ++++-- .../resources/dsl/kts/12-layers.alchemist.kts | 37 ++++++++++-- .../dsl/kts/14-exporters.alchemist.kts | 11 ++++ .../dsl/kts/15-variables.alchemist.kts | 30 ++++++---- .../dsl/kts/18-properties.alchemist.kts | 11 ++++ .../dsl/kts/19-performance.alchemist.kts | 9 +++ alchemist-maps/build.gradle.kts | 2 +- alchemist-physics/build.gradle.kts | 2 +- alchemist-smartcam/build.gradle.kts | 2 +- alchemist-test/build.gradle.kts | 2 +- gradle/libs.versions.toml | 4 +- settings.gradle.kts | 2 +- 48 files changed, 196 insertions(+), 125 deletions(-) rename {alchemist-dsl-processor => alchemist-factories-generator}/build.gradle.kts (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/InjectableConstructor.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/TypePosition.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclarationExtensions.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSValueParameterExtensions.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/ListExtensions.kt (100%) rename {alchemist-dsl-processor => alchemist-factories-generator}/src/jvmMain/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider (100%) rename alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/{sapere => incarnations}/SAPEREIncarnation.java (98%) rename alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/{ => incarnations}/ScafiIncarnation.scala (97%) rename alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/{implementations => scafi}/actions/RunScafiProgram.scala (97%) rename alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/{implementations => scafi}/actions/SendScafiMessage.scala (93%) rename alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/{implementations => scafi}/conditions/ScafiComputationalRoundComplete.scala (86%) rename alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/{implementations => scafi}/nodes/NodeManager.scala (87%) rename alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/{implementations/nodes => scafi/properties}/ScafiDevice.scala (88%) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 07673e99d9..c451d7a065 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -19,7 +19,6 @@ diff --git a/alchemist-cognitive-agents/build.gradle.kts b/alchemist-cognitive-agents/build.gradle.kts index 0176f274aa..7d43526a26 100644 --- a/alchemist-cognitive-agents/build.gradle.kts +++ b/alchemist-cognitive-agents/build.gradle.kts @@ -15,7 +15,7 @@ plugins { } dependencies { - ksp(alchemist("dsl-processor")) + ksp(alchemist("factories-generator")) api(alchemist("api")) diff --git a/alchemist-euclidean-geometry/build.gradle.kts b/alchemist-euclidean-geometry/build.gradle.kts index 39cf748cff..0c00b1f526 100644 --- a/alchemist-euclidean-geometry/build.gradle.kts +++ b/alchemist-euclidean-geometry/build.gradle.kts @@ -15,7 +15,7 @@ plugins { } dependencies { - ksp(alchemist("dsl-processor")) + ksp(alchemist("factories-generator")) api(alchemist("api")) api(alchemist("implementationbase")) diff --git a/alchemist-dsl-processor/build.gradle.kts b/alchemist-factories-generator/build.gradle.kts similarity index 100% rename from alchemist-dsl-processor/build.gradle.kts rename to alchemist-factories-generator/build.gradle.kts diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessorProvider.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/InjectableConstructor.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/InjectableConstructor.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/InjectableConstructor.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/InjectableConstructor.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/TypePosition.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/TypePosition.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/TypePosition.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/datatypes/TypePosition.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclarationExtensions.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclarationExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclarationExtensions.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSDeclarationExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSFunctionDeclarationExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeArgumentExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSTypeReferenceExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSValueParameterExtensions.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSValueParameterExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSValueParameterExtensions.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/KSValueParameterExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/ListExtensions.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/ListExtensions.kt similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/ListExtensions.kt rename to alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/extensions/ListExtensions.kt diff --git a/alchemist-dsl-processor/src/jvmMain/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/alchemist-factories-generator/src/jvmMain/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider similarity index 100% rename from alchemist-dsl-processor/src/jvmMain/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider rename to alchemist-factories-generator/src/jvmMain/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider diff --git a/alchemist-implementationbase/build.gradle.kts b/alchemist-implementationbase/build.gradle.kts index 068b900bbb..cada7f26bf 100644 --- a/alchemist-implementationbase/build.gradle.kts +++ b/alchemist-implementationbase/build.gradle.kts @@ -14,7 +14,7 @@ plugins { } dependencies { - ksp(alchemist("dsl-processor")) + ksp(alchemist("factories-generator")) api(alchemist("api")) api(alchemist("maintenance-tooling")) diff --git a/alchemist-incarnation-biochemistry/build.gradle.kts b/alchemist-incarnation-biochemistry/build.gradle.kts index 49ad5a69b7..aed0314cee 100644 --- a/alchemist-incarnation-biochemistry/build.gradle.kts +++ b/alchemist-incarnation-biochemistry/build.gradle.kts @@ -25,7 +25,7 @@ plugins { dependencies { antlr(libs.antlr4) - ksp(alchemist("dsl-processor")) + ksp(alchemist("factories-generator")) api(alchemist("implementationbase")) api(alchemist("euclidean-geometry")) diff --git a/alchemist-incarnation-protelis/build.gradle.kts b/alchemist-incarnation-protelis/build.gradle.kts index 35417fc9ab..dcb3a8e239 100644 --- a/alchemist-incarnation-protelis/build.gradle.kts +++ b/alchemist-incarnation-protelis/build.gradle.kts @@ -24,7 +24,7 @@ plugins { dependencies { // KSP - ksp(alchemist("dsl-processor")) + ksp(alchemist("factories-generator")) // API api(alchemist("api")) api(alchemist("implementationbase")) diff --git a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/properties/ProtelisDevice.kt b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/properties/ProtelisDevice.kt index 644cf740ce..4b14dc50c4 100644 --- a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/properties/ProtelisDevice.kt +++ b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/properties/ProtelisDevice.kt @@ -14,9 +14,9 @@ import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.NodeProperty import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.Reaction +import it.unibo.alchemist.model.incarnations.ProtelisIncarnation import it.unibo.alchemist.model.protelis.AlchemistExecutionContext import it.unibo.alchemist.model.protelis.AlchemistNetworkManager -import it.unibo.alchemist.model.protelis.ProtelisIncarnation import it.unibo.alchemist.model.protelis.actions.RunProtelisProgram import it.unibo.alchemist.model.protelis.actions.SendToNeighbor import org.protelis.lang.datatype.DeviceUID diff --git a/alchemist-incarnation-sapere/build.gradle.kts b/alchemist-incarnation-sapere/build.gradle.kts index dbe59f9401..89a547679f 100644 --- a/alchemist-incarnation-sapere/build.gradle.kts +++ b/alchemist-incarnation-sapere/build.gradle.kts @@ -14,7 +14,7 @@ plugins { } dependencies { - ksp(alchemist("dsl-processor")) + ksp(alchemist("factories-generator")) api(alchemist("api")) api(alchemist("sapere-mathexp")) implementation(alchemist("implementationbase")) diff --git a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/SAPEREIncarnation.java b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java similarity index 98% rename from alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/SAPEREIncarnation.java rename to alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java index 7f162fbff4..43c8489738 100644 --- a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/SAPEREIncarnation.java +++ b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java @@ -7,7 +7,7 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.model.sapere; +package it.unibo.alchemist.model.incarnations; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import it.unibo.alchemist.model.Action; @@ -20,6 +20,8 @@ import it.unibo.alchemist.model.Position; import it.unibo.alchemist.model.Reaction; import it.unibo.alchemist.model.TimeDistribution; +import it.unibo.alchemist.model.sapere.ILsaMolecule; +import it.unibo.alchemist.model.sapere.ILsaNode; import it.unibo.alchemist.model.sapere.actions.LsaAllNeighborsAction; import it.unibo.alchemist.model.sapere.actions.LsaRandomNeighborAction; import it.unibo.alchemist.model.sapere.actions.LsaStandardAction; diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/ScafiIncarnation.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala similarity index 97% rename from alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/ScafiIncarnation.scala rename to alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala index 1384e5b2f1..8462a16c6a 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/ScafiIncarnation.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala @@ -6,17 +6,17 @@ * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.model +package it.unibo.alchemist.model.incarnations -import it.unibo.alchemist.model.ScafiIncarnationUtils._ -import it.unibo.alchemist.model.implementations.actions.{RunScafiProgram, SendScafiMessage} -import it.unibo.alchemist.model.implementations.conditions.ScafiComputationalRoundComplete import it.unibo.alchemist.model.implementations.nodes.ScafiDevice import it.unibo.alchemist.model.molecules.SimpleMolecule import it.unibo.alchemist.model.nodes.GenericNode import it.unibo.alchemist.model.reactions.{ChemicalReaction, Event} import it.unibo.alchemist.model.timedistributions.{DiracComb, ExponentialTime} import it.unibo.alchemist.model.times.DoubleTime +import it.unibo.alchemist.model._ +import it.unibo.alchemist.model.scafi.actions.{RunScafiProgram, SendScafiMessage} +import it.unibo.alchemist.model.scafi.conditions.ScafiComputationalRoundComplete import it.unibo.alchemist.scala.ScalaInterpreter import org.apache.commons.math3.random.RandomGenerator diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/actions/RunScafiProgram.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/RunScafiProgram.scala similarity index 97% rename from alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/actions/RunScafiProgram.scala rename to alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/RunScafiProgram.scala index 6ac37e7897..616e0712b6 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/actions/RunScafiProgram.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/RunScafiProgram.scala @@ -1,11 +1,12 @@ /* - * Copyright (C) 2010-2019, Danilo Pianini and contributors listed in the main project's alchemist/build.gradle file. + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.model.implementations.actions +package it.unibo.alchemist.model.scafi.actions import it.unibo.alchemist.model.actions.AbstractLocalAction import it.unibo.alchemist.model.{Node, Position, Reaction} diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/actions/SendScafiMessage.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/SendScafiMessage.scala similarity index 93% rename from alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/actions/SendScafiMessage.scala rename to alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/SendScafiMessage.scala index f8bbeffd3f..6bc62051b8 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/actions/SendScafiMessage.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/SendScafiMessage.scala @@ -1,13 +1,13 @@ /* - * Copyright (C) 2010-2019, Danilo Pianini and contributors - * listed in the main project's alchemist/build.gradle.kts file. + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.model.implementations.actions +package it.unibo.alchemist.model.scafi.actions import it.unibo.alchemist.model.{Node, Position, Reaction, ScafiIncarnationUtils} import it.unibo.alchemist.model.ScafiIncarnationUtils._ diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/conditions/ScafiComputationalRoundComplete.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/conditions/ScafiComputationalRoundComplete.scala similarity index 86% rename from alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/conditions/ScafiComputationalRoundComplete.scala rename to alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/conditions/ScafiComputationalRoundComplete.scala index 06caf18dce..05b14c5cac 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/conditions/ScafiComputationalRoundComplete.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/conditions/ScafiComputationalRoundComplete.scala @@ -1,17 +1,17 @@ /* - * Copyright (C) 2010-2019, Danilo Pianini and contributors - * listed in the main project's alchemist/build.gradle.kts file. + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.model.implementations.conditions +package it.unibo.alchemist.model.scafi.conditions import it.unibo.alchemist.model.ScafiIncarnationUtils import it.unibo.alchemist.model.conditions.AbstractCondition -import it.unibo.alchemist.model.implementations.actions.RunScafiProgram import it.unibo.alchemist.model.implementations.nodes.ScafiDevice +import it.unibo.alchemist.model.scafi.actions.RunScafiProgram import it.unibo.alchemist.model.{Condition, Context, Node, Reaction} final class ScafiComputationalRoundComplete[T](val device: ScafiDevice[T], val program: RunScafiProgram[_, _]) diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/nodes/NodeManager.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/nodes/NodeManager.scala similarity index 87% rename from alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/nodes/NodeManager.scala rename to alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/nodes/NodeManager.scala index 61b631ed10..ed8a088e93 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/nodes/NodeManager.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/nodes/NodeManager.scala @@ -1,11 +1,12 @@ /* - * Copyright (C) 2010-2019, Danilo Pianini and contributors listed in the main project's alchemist/build.gradle file. + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.model.implementations.nodes +package it.unibo.alchemist.model.scafi.nodes import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.molecules.SimpleMolecule diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/nodes/ScafiDevice.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/properties/ScafiDevice.scala similarity index 88% rename from alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/nodes/ScafiDevice.scala rename to alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/properties/ScafiDevice.scala index 169b1a861f..5d2542b310 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/implementations/nodes/ScafiDevice.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/properties/ScafiDevice.scala @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -7,11 +7,12 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.model.implementations.nodes +package it.unibo.alchemist.model.scafi.properties +import it.unibo.alchemist.model.scafi.actions.{RunScafiProgram, SendScafiMessage} import it.unibo.alchemist.model.{Node, NodeProperty} -import it.unibo.alchemist.model.implementations.actions.{RunScafiProgram, SendScafiMessage} import org.slf4j.LoggerFactory + import scala.jdk.CollectionConverters._ class ScafiDevice[E](node: Node[E]) extends NodeProperty[E] { diff --git a/alchemist-loading/build.gradle.kts b/alchemist-loading/build.gradle.kts index 9e0935022d..d457299f52 100644 --- a/alchemist-loading/build.gradle.kts +++ b/alchemist-loading/build.gradle.kts @@ -10,23 +10,25 @@ import Libs.alchemist import Libs.incarnation -/* - * Copyright (C) 2010-2019) Danilo Pianini and contributors listed in the main project"s alchemist/build.gradle file. - * - * This file is part of Alchemist) and is distributed under the terms of the - * GNU General Public License) with a linking exception) - * as described in the file LICENSE in the Alchemist distribution"s top directory. - */ plugins { id("kotlin-jvm-convention") + kotlin("plugin.scripting") } dependencies { + ksp(alchemist("factories-generator")) + api(alchemist("api")) api(alchemist("implementationbase")) implementation(alchemist("engine")) implementation(alchemist("euclidean-geometry")) + implementation(kotlin("reflect")) + implementation(kotlin("script-runtime")) + implementation(kotlin("scripting-common")) + implementation(kotlin("scripting-ide-services")) + implementation(kotlin("scripting-jvm")) + implementation(kotlin("scripting-jvm-host")) implementation(libs.apache.commons.lang3) implementation(libs.arrow.core) implementation(libs.dsiutils) @@ -41,10 +43,6 @@ dependencies { implementation(libs.mongodb) implementation(libs.snakeyaml) - implementation("org.jetbrains.kotlin:kotlin-scripting-common:${libs.versions.kotlin.get()}") - implementation("org.jetbrains.kotlin:kotlin-scripting-jvm:${libs.versions.kotlin.get()}") - implementation("org.jetbrains.kotlin:kotlin-scripting-jvm-host:${libs.versions.kotlin.get()}") - runtimeOnly(libs.groovy.jsr223) runtimeOnly(kotlin("scripting-jsr223")) runtimeOnly(libs.scala.compiler) @@ -57,9 +55,6 @@ dependencies { testImplementation(libs.appdirs) testImplementation(libs.caffeine) testImplementation(libs.embedmongo) - implementation(kotlin("script-runtime")) - - ksp(project(":alchemist-dsl-processor")) } kotlin { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index c1fd0d59f8..7414930cc5 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -31,6 +31,8 @@ import it.unibo.alchemist.model.deployments.grid import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.deployments.polygon import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.incarnations.ProtelisIncarnation +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.layers.StepLayer import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.maps.actions.ReproduceGPSTrace @@ -40,10 +42,8 @@ import it.unibo.alchemist.model.maps.environments.oSMEnvironment import it.unibo.alchemist.model.nodes.testNode import it.unibo.alchemist.model.positionfilters.Rectangle import it.unibo.alchemist.model.positions.Euclidean2DPosition -import it.unibo.alchemist.model.protelis.ProtelisIncarnation import it.unibo.alchemist.model.reactions.Event import it.unibo.alchemist.model.sapere.ILsaMolecule -import it.unibo.alchemist.model.sapere.SAPEREIncarnation import it.unibo.alchemist.model.terminators.AfterTime import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.timedistributions.DiracComb @@ -54,7 +54,7 @@ import it.unibo.alchemist.test.globalTestReaction import org.apache.commons.math3.random.MersenneTwister object DslLoaderFunctions { - fun > test01Nodes(): Loader { + fun test01Nodes(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(5.0) @@ -65,7 +65,7 @@ object DslLoaderFunctions { } } - fun > test02ManyNodes(): Loader { + fun test02ManyNodes(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { simulationGenerator = MersenneTwister(10L) @@ -85,7 +85,7 @@ object DslLoaderFunctions { } } } - fun > test03Grid(): Loader { + fun test03Grid(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) @@ -104,7 +104,7 @@ object DslLoaderFunctions { } } } - fun > test05Content(): Loader { + fun test05Content(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) @@ -129,7 +129,7 @@ object DslLoaderFunctions { } } } - fun > test06ContentFiltered(): Loader { + fun test06ContentFiltered(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) @@ -156,7 +156,7 @@ object DslLoaderFunctions { } } - fun > test07Programs(): Loader { + fun test07Programs(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) @@ -190,7 +190,7 @@ object DslLoaderFunctions { } } } - fun > test08ProtelisPrograms(): Loader = simulation(ProtelisIncarnation()) { + fun test08ProtelisPrograms(): Loader = simulation(ProtelisIncarnation()) { deployments { deploy(point(1.5, 0.5)) { programs { @@ -213,7 +213,7 @@ object DslLoaderFunctions { } } } - fun > test09TimeDistribution(): Loader { + fun test09TimeDistribution(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) @@ -240,7 +240,7 @@ object DslLoaderFunctions { } } } - fun test10Environment(): Loader { + fun test10Environment(): Loader { val incarnation = SAPEREIncarnation() val env = OSMEnvironment(incarnation, "vcm.pbf", false) return simulation(incarnation, { env }) { @@ -328,7 +328,7 @@ object DslLoaderFunctions { +globalTestReaction(DiracComb(1.0)) } } - fun > test14Exporters(): Loader = simulation(ProtelisIncarnation()) { + fun test14Exporters(): Loader = simulation(ProtelisIncarnation()) { exporter { type = CSVExporter( "test_export_interval", @@ -345,16 +345,15 @@ object DslLoaderFunctions { ) } } - fun > test15Variables(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { + fun test15Variables(): Loader { + return simulation(SAPEREIncarnation()) { val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) val mSize by variable { -size } val sourceStart by variable { mSize / 10.0 } val sourceSize by variable { size / 5.0 } - terminators { +AfterTime(DoubleTime(1.0)) } + terminators { +AfterTime, Euclidean2DPosition>(DoubleTime(1.0)) } networkModel = ConnectWithinDistance(0.5) deployments { deploy( @@ -386,7 +385,7 @@ object DslLoaderFunctions { } } - fun > test16ProgramsFilters(): Loader { + fun test16ProgramsFilters(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) @@ -418,7 +417,7 @@ object DslLoaderFunctions { } } } - fun > test17CustomNodes(): Loader { + fun test17CustomNodes(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { deployments { @@ -435,7 +434,7 @@ object DslLoaderFunctions { } } } - fun > test18NodeProperties(): Loader { + fun test18NodeProperties(): Loader { val incarnation = SAPEREIncarnation() val environment = Continuous2DEnvironment(incarnation) return simulation(incarnation, { environment }) { @@ -462,7 +461,7 @@ object DslLoaderFunctions { } } } - fun > test20Actions(): Loader = simulation(SAPEREIncarnation(), { + fun test20Actions(): Loader = simulation(SAPEREIncarnation(), { oSMEnvironment() }) { networkModel = ConnectWithinDistance(1000.0) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt index 2b886c5c80..c240f4a031 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt @@ -20,7 +20,6 @@ class KotlinDslProviderTest { @Test fun `a simple textual Kotlin DSL script should load`() { val script = """ - import it.unibo.alchemist.model.sapere.SAPEREIncarnation simulation(SAPEREIncarnation()) { networkModel = ConnectWithinDistance(5.0) deployments { @@ -36,7 +35,7 @@ class KotlinDslProviderTest { } @Test - fun loadFromFile() { + fun `loading the variables test from the Kotlin Script should provide the same value of the YAML file`() { val dslUrl = requireNotNull(this.javaClass.getResource("/dsl/kts/15-variables.alchemist.kts")) { "Resource /dsl/kts/15-variables.alchemist.kts not found on test classpath" } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt index 661b80a173..cd5b569e85 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt @@ -14,52 +14,52 @@ import org.junit.jupiter.api.Test class SimulationsComparisons { @Test - fun > test01() { - { DslLoaderFunctions.test01Nodes() }.shouldEqual("dsl/yml/01-nodes.yml") + fun test01() { + { DslLoaderFunctions.test01Nodes() }.shouldEqual("dsl/yml/01-nodes.yml") } @Test - fun > test02() { - { DslLoaderFunctions.test02ManyNodes() }.shouldEqual("dsl/yml/02-manynodes.yml") + fun test02() { + { DslLoaderFunctions.test02ManyNodes() }.shouldEqual("dsl/yml/02-manynodes.yml") } @Test - fun > test03() { - { DslLoaderFunctions.test03Grid() }.shouldEqual("dsl/yml/03-grid.yml") + fun test03() { + { DslLoaderFunctions.test03Grid() }.shouldEqual("dsl/yml/03-grid.yml") } @Test - fun > test05() { - { DslLoaderFunctions.test05Content() }.shouldEqual("dsl/yml/05-content.yml") + fun test05() { + { DslLoaderFunctions.test05Content() }.shouldEqual("dsl/yml/05-content.yml") } @Test - fun > test06() { - { DslLoaderFunctions.test06ContentFiltered() }.shouldEqual("dsl/yml/06-filters.yml") + fun test06() { + { DslLoaderFunctions.test06ContentFiltered() }.shouldEqual("dsl/yml/06-filters.yml") } @Test - fun > test07() { - { DslLoaderFunctions.test07Programs() }.shouldEqual("dsl/yml/07-program.yml") + fun test07() { + { DslLoaderFunctions.test07Programs() }.shouldEqual("dsl/yml/07-program.yml") } @Test - fun > test08() { - DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/yml/08-protelisprogram.yml") + fun test08() { + DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/yml/08-protelisprogram.yml") } @Test - fun > test09() { - { DslLoaderFunctions.test09TimeDistribution() }.shouldEqual("dsl/yml/09-timedistribution.yml") + fun test09() { + { DslLoaderFunctions.test09TimeDistribution() }.shouldEqual("dsl/yml/09-timedistribution.yml") } @Test - fun > test10() { - { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/yml/10-environment.yml") + fun test10() { + { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/yml/10-environment.yml") } @Test - fun > test11() { + fun test11() { { DslLoaderFunctions.test11monitors() }.shouldEqual("dsl/yml/11-monitors.yml") } @@ -75,17 +75,17 @@ class SimulationsComparisons { @Test fun > test14() { - { DslLoaderFunctions.test14Exporters() }.shouldEqual("dsl/yml/14-exporters.yml") + { DslLoaderFunctions.test14Exporters() }.shouldEqual("dsl/yml/14-exporters.yml") } @Test - fun > test15() { - { DslLoaderFunctions.test15Variables() }.shouldEqual("dsl/yml/15-variables.yml") + fun test15() { + { DslLoaderFunctions.test15Variables() }.shouldEqual("dsl/yml/15-variables.yml") } @Test - fun > test16() { - { DslLoaderFunctions.test16ProgramsFilters() } + fun test16() { + { DslLoaderFunctions.test16ProgramsFilters() } .shouldEqual( "dsl/yml/16-programsfilters.yml", targetTime = 10.0, @@ -93,18 +93,18 @@ class SimulationsComparisons { } @Test - fun > test17() { - { DslLoaderFunctions.test17CustomNodes() }.shouldEqual("dsl/yml/17-customnodes.yml") + fun test17() { + { DslLoaderFunctions.test17CustomNodes() }.shouldEqual("dsl/yml/17-customnodes.yml") } @Test - fun > test18() { - { DslLoaderFunctions.test18NodeProperties() }.shouldEqual("dsl/yml/18-properties.yml") + fun test18() { + { DslLoaderFunctions.test18NodeProperties() }.shouldEqual("dsl/yml/18-properties.yml") } @Test - fun > test20() { - { DslLoaderFunctions.test20Actions() }.shouldEqual( + fun test20() { + { DslLoaderFunctions.test20Actions() }.shouldEqual( "dsl/yml/20-move.yml", targetTime = 10.0, ) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt index f2fea3966a..861289db92 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -11,7 +11,7 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.model.deployments.Point -import it.unibo.alchemist.model.sapere.SAPEREIncarnation +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.sapere.molecules.LsaMolecule import org.junit.jupiter.api.Test diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index ee91409381..8f5fa51817 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -12,7 +12,7 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point -import it.unibo.alchemist.model.sapere.SAPEREIncarnation +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import org.junit.jupiter.api.Test class TestDeployments { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt index 820832dc8a..740f98ae36 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt @@ -10,8 +10,8 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.Dsl.simulation +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance -import it.unibo.alchemist.model.sapere.SAPEREIncarnation import org.junit.jupiter.api.Test class TestSimulations { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt index d8d199ab8f..767358056b 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -17,7 +17,7 @@ import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.sapere.SAPEREIncarnation +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.sapere.molecules.LsaMolecule import org.junit.jupiter.api.Test diff --git a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts index 941bd2c9ed..ecda9f6ab8 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts @@ -1,8 +1,13 @@ -import another.location.SimpleMonitor -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation -import it.unibo.alchemist.boundary.dsl.Dsl.simulation - /* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package dsl.kts/* * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * @@ -10,9 +15,10 @@ import it.unibo.alchemist.boundary.dsl.Dsl.simulation * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ +import another.location.SimpleMonitor +import it.unibo.alchemist.boundary.dsl.Dsl.simulation -val incarnation = SAPERE.incarnation() -simulation(incarnation) { +simulation(SAPEREIncarnation()) { monitors { +SimpleMonitor() } diff --git a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts index 7643de365a..403660c284 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts @@ -1,17 +1,44 @@ -val incarnation = SAPERE.incarnation() +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package dsl.kts + +val incarnation = SAPEREIncarnation() simulation(incarnation) { layer { molecule = "A" - layer = StepLayer(2.0, 2.0, 100.0, 0.0) + layer = StepLayer( + 2.0, + 2.0, + incarnation.createConcentration("100"), + incarnation.createConcentration("0"), + ) } layer { molecule = "B" - layer = StepLayer(-2.0, -2.0, 0.0, 100.0) + layer = StepLayer( + -2.0, + -2.0, + incarnation.createConcentration("0"), + incarnation.createConcentration("100"), + ) } deployments { deploy( - grid(-5.0, -5.0, 5.0, 5.0, 0.25, - 0.1, 0.1, + grid( + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.1, + 0.1, ), ) { all { diff --git a/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts index 82ebaf280d..703c8ee878 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts @@ -1,3 +1,14 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package dsl.kts + import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation diff --git a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts index 6bc0077881..60502f73f8 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts @@ -1,25 +1,37 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation -import it.unibo.alchemist.boundary.dsl.Dsl.simulation +package dsl.kts -val incarnation = SAPERE.incarnation() -simulation(incarnation) { +simulation(SAPEREIncarnation()) { val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) val mSize by variable { -size } val sourceStart by variable { mSize / 10.0 } val sourceSize by variable { size / 5.0 } - + terminators { +AfterTime, Euclidean2DPosition>(DoubleTime(1.0)) } networkModel = ConnectWithinDistance(0.5) deployments { deploy( grid( - mSize, mSize, size, size, - 0.25, 0.25, 0.1, 0.1, + mSize, + mSize, + size, + size, + 0.25, + 0.25, + 0.1, + 0.1, ), ) { - inside(RectangleFilter(sourceStart, sourceStart, sourceSize, sourceSize)) { + inside(Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { molecule = "token, 0, []" } programs { @@ -34,5 +46,3 @@ simulation(incarnation) { } } } - - diff --git a/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts index 40adb4b227..769afa7ca8 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts @@ -1,3 +1,14 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package dsl.kts + import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation diff --git a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts index 420f9be133..9f158abbf9 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts @@ -1,4 +1,13 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +package dsl.kts import another.location.SimpleMonitor import it.unibo.alchemist.boundary.dsl.Dsl.incarnation import it.unibo.alchemist.boundary.dsl.Dsl.simulation diff --git a/alchemist-maps/build.gradle.kts b/alchemist-maps/build.gradle.kts index 5a2eda69a0..29c74442dd 100644 --- a/alchemist-maps/build.gradle.kts +++ b/alchemist-maps/build.gradle.kts @@ -15,7 +15,7 @@ plugins { } dependencies { - ksp(alchemist("dsl-processor")) + ksp(alchemist("factories-generator")) api(alchemist("api")) implementation(alchemist("implementationbase")) diff --git a/alchemist-physics/build.gradle.kts b/alchemist-physics/build.gradle.kts index f988562eaf..bf59170f29 100644 --- a/alchemist-physics/build.gradle.kts +++ b/alchemist-physics/build.gradle.kts @@ -14,7 +14,7 @@ plugins { } dependencies { - ksp(alchemist("dsl-processor")) + ksp(alchemist("factories-generator")) api(alchemist("api")) api(alchemist("euclidean-geometry")) implementation(alchemist("implementationbase")) diff --git a/alchemist-smartcam/build.gradle.kts b/alchemist-smartcam/build.gradle.kts index ccebe83857..de06d07436 100644 --- a/alchemist-smartcam/build.gradle.kts +++ b/alchemist-smartcam/build.gradle.kts @@ -15,7 +15,7 @@ plugins { } dependencies { - ksp(alchemist("dsl-processor")) + ksp(alchemist("factories-generator")) api(alchemist("api")) implementation(alchemist("euclidean-geometry")) implementation(alchemist("implementationbase")) diff --git a/alchemist-test/build.gradle.kts b/alchemist-test/build.gradle.kts index 8cb7928331..a2d8b83b98 100644 --- a/alchemist-test/build.gradle.kts +++ b/alchemist-test/build.gradle.kts @@ -15,7 +15,7 @@ plugins { } dependencies { - ksp(alchemist("dsl-processor")) + ksp(alchemist("factories-generator")) api(alchemist("api")) api(alchemist("engine")) api(alchemist("loading")) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cd57fba5ff..24c4ec1a0b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -78,13 +78,13 @@ kotlin-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-co kotlin-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } kotlin-jvm-plugin = { module = "org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin", version.ref = "kotlin" } kotlin-multiplatform-plugin = { module = "org.jetbrains.kotlin.multiplatform:org.jetbrains.kotlin.multiplatform.gradle.plugin", version.ref = "kotlin" } -kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } -kotlin-test-annotations = { module = "org.jetbrains.kotlin:kotlin-test-annotations-common", version.ref = "kotlin" } kotlin-power-assert-plugin = { module = "org.jetbrains.kotlin.plugin.power-assert:org.jetbrains.kotlin.plugin.power-assert.gradle.plugin", version.ref = "kotlin" } kotlin-quality-assurance-plugin = "org.danilopianini.gradle-kotlin-qa:org.danilopianini.gradle-kotlin-qa.gradle.plugin:0.100.0" kotlin-react = { module = "org.jetbrains.kotlin-wrappers:kotlin-react", version.ref = "react" } kotlin-react-dom = { module = "org.jetbrains.kotlin-wrappers:kotlin-react-dom", version.ref = "react" } kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } +kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } +kotlin-test-annotations = { module = "org.jetbrains.kotlin:kotlin-test-annotations-common", version.ref = "kotlin" } ksp-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" } ksp = { module = "com.google.devtools.ksp:symbol-processing", version.ref = "ksp" } kotlinx-atomicfu-runtime = { module = "org.jetbrains.kotlin:kotlinx-atomicfu-runtime", version.ref = "kotlin" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 2d9de93466..45f1121e7b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,9 +16,9 @@ include( "alchemist-api", "alchemist-composeui", "alchemist-cognitive-agents", - "alchemist-dsl-processor", "alchemist-engine", "alchemist-euclidean-geometry", + "alchemist-factories-generator", "alchemist-full", "alchemist-graphql", "alchemist-graphql-surrogates", From 2a220c6f3efed477046e702a1e505cef02ea5c7b Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 23 Jan 2026 14:50:08 +0100 Subject: [PATCH 135/196] refactor: another gigantic refactor, holy shit --- .../ProtelisIncarnation.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) rename alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/{protelis => incarnations}/ProtelisIncarnation.kt (97%) diff --git a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/ProtelisIncarnation.kt b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt similarity index 97% rename from alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/ProtelisIncarnation.kt rename to alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt index 21cdbe71cc..8fc639544d 100644 --- a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/ProtelisIncarnation.kt +++ b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt @@ -6,7 +6,8 @@ * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.model.protelis + +package it.unibo.alchemist.model.incarnations import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheLoader @@ -44,6 +45,7 @@ import java.util.Optional import java.util.concurrent.Semaphore import java.util.concurrent.TimeUnit import javax.annotation.Nonnull +import kotlin.text.get import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator import org.protelis.lang.ProtelisLoader @@ -248,10 +250,11 @@ class ProtelisIncarnation

> : Incarnation { private val nodeRef = WeakReference(node) private val hash = Objects.hash(molecule, property, node) - val node: Node get() = - checkNotNull(nodeRef.get()) { - "Memory management issue: a Protelis node has been garbage-collected while still in use." - } + val node: Node + get() = + checkNotNull(nodeRef.get()) { + "Memory management issue: a Protelis node has been garbage-collected while still in use." + } override fun equals(other: Any?) = other is CacheKey && other.nodeRef.get() === nodeRef.get() && @@ -293,7 +296,7 @@ class ProtelisIncarnation

> : Incarnation { } /** - * An [ExecutionEnvironment] that can read and shadow the content of a + * An [org.protelis.vm.ExecutionEnvironment] that can read and shadow the content of a * Node, but cannot modify it. This is used to prevent badly written * properties from interacting with the simulation flow. * From b17fe00e3e255daf51b3311cef90a2280541730e Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 23 Jan 2026 15:10:35 +0100 Subject: [PATCH 136/196] chore: try to make the scripting engine work in the ide --- .../boundary/dsl/scripting/AlchemistScript.kt | 2 +- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 62 +++++++++---------- .../dsl/kts/11-monitors.alchemist.kts | 9 --- 3 files changed, 31 insertions(+), 42 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt index 7395db65fc..030261aac2 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt @@ -27,7 +27,7 @@ import kotlin.script.experimental.jvm.jvm fileExtension = "alchemist.kts", compilationConfiguration = AlchemistCompilationConfiguration::class, ) -interface AlchemistScript +abstract class AlchemistScript /** * Compilation configuration for Alchemist scripts. diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 7414930cc5..c900669c6f 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -345,40 +345,38 @@ object DslLoaderFunctions { ) } } - fun test15Variables(): Loader { - return simulation(SAPEREIncarnation()) { - val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) - val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + fun test15Variables(): Loader = simulation(SAPEREIncarnation()) { + val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) + val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) - val mSize by variable { -size } - val sourceStart by variable { mSize / 10.0 } - val sourceSize by variable { size / 5.0 } - terminators { +AfterTime, Euclidean2DPosition>(DoubleTime(1.0)) } - networkModel = ConnectWithinDistance(0.5) - deployments { - deploy( - grid( - mSize, - mSize, - size, - size, - 0.25, - 0.25, - 0.1, - 0.1, - ), - ) { - inside(Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { - molecule = "token, 0, []" + val mSize by variable { -size } + val sourceStart by variable { mSize / 10.0 } + val sourceSize by variable { size / 5.0 } + terminators { +AfterTime, Euclidean2DPosition>(DoubleTime(1.0)) } + networkModel = ConnectWithinDistance(0.5) + deployments { + deploy( + grid( + mSize, + mSize, + size, + size, + 0.25, + 0.25, + 0.1, + 0.1, + ), + ) { + inside(Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { + molecule = "token, 0, []" + } + programs { + all { + timeDistribution(rate.toString()) + program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" } - programs { - all { - timeDistribution(rate.toString()) - program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" - } - all { - program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" - } + all { + program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" } } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts index ecda9f6ab8..7c3e8116bd 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts @@ -6,15 +6,6 @@ * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ - -package dsl.kts/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ import another.location.SimpleMonitor import it.unibo.alchemist.boundary.dsl.Dsl.simulation From 681b180fea7563d3184f4590584dd0f814769f89 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 25 Jan 2026 16:56:39 +0100 Subject: [PATCH 137/196] refactor: fix scafi and refactor repetitive test --- .../unibo/alchemist/util/TestDiameterUtils.kt | 2 +- ...TestEnvironmentsDiameterWithHopDistance.kt | 8 +- .../model/protelis/TestGetPosition.kt | 1 + .../model/incarnations/ScafiIncarnation.scala | 5 +- .../scafi/ScafiIncarnationForAlchemist.scala | 2 +- .../model/scafi/actions/RunScafiProgram.scala | 2 +- .../scafi/actions/SendScafiMessage.scala | 7 +- .../ScafiComputationalRoundComplete.scala | 4 +- .../alchemist/scala/PimpMyAlchemist.scala | 2 +- alchemist-kotlinscript/build.gradle.kts | 10 +++ .../alchemist/kotlinscript/AlchemistScript.kt | 89 +++++++++++++++++++ ...ibo.alchemist.kotlinscript.AlchemistScript | 0 alchemist-loading/build.gradle.kts | 3 +- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 10 +-- .../alchemist/dsl/KotlinDslProviderTest.kt | 56 +++++------- .../alchemist/dsl/LayerComparisonUtils.kt | 2 +- .../dsl/kts/11-monitors.alchemist.kts | 2 + .../resources/dsl/kts/12-layers.alchemist.kts | 14 ++- .../dsl/kts/14-exporters.alchemist.kts | 5 +- .../dsl/kts/15-variables.alchemist.kts | 6 +- .../dsl/kts/18-properties.alchemist.kts | 10 +-- .../src/test/resources/dsl/yml/12-layers.yml | 2 +- gradle/libs.versions.toml | 6 +- settings.gradle.kts | 1 + 24 files changed, 170 insertions(+), 79 deletions(-) create mode 100644 alchemist-kotlinscript/build.gradle.kts create mode 100644 alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt create mode 100644 alchemist-kotlinscript/src/main/resources/META-INF/kotlin/script/templates/it.unibo.alchemist.kotlinscript.AlchemistScript diff --git a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt index a9af66138e..4d56c5465f 100644 --- a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt +++ b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt @@ -11,10 +11,10 @@ package it.unibo.alchemist.util import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.incarnations.ProtelisIncarnation import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.nodes.GenericNode import it.unibo.alchemist.model.positions.Euclidean2DPosition -import it.unibo.alchemist.model.protelis.ProtelisIncarnation import it.unibo.alchemist.util.Environments.isNetworkSegmented import it.unibo.alchemist.util.Environments.networkDiameter import kotlin.test.assertTrue diff --git a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameterWithHopDistance.kt b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameterWithHopDistance.kt index b6ea6b8028..58ca8d3cc3 100644 --- a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameterWithHopDistance.kt +++ b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameterWithHopDistance.kt @@ -19,19 +19,19 @@ import org.junit.jupiter.api.Test object TestEnvironmentsDiameterWithHopDistance { private infix fun Environment.withHopDistanceMustHave(expected: Subnetworks) = - assertEquals(expected.count, allSubNetworksWithHopDistance().size) + assertEquals(expected.count, allSubNetworksWithHopDistance().size) private fun Environment.specificNodeInASegmentedNetworkShouldHaveHopDiameter( index: Int, expected: Double, - ) = { + ) { require(index < nodes.size) - assertEquals(expected, allSubNetworksByNodeWithHopDistance()[nodes[index]]?.diameter!!) + assertEquals(expected, allSubNetworksByNodeWithHopDistance()[nodes[index]]?.diameter!!) } private infix fun Environment.mustNotBeSegmentedAndHaveHopDiameter(expected: Double) { assertFalse(isNetworkSegmented()) - assertEquals(expected, allSubNetworksWithHopDistance().single().diameter) + assertEquals(expected, allSubNetworksWithHopDistance().single().diameter) } @Test diff --git a/alchemist-incarnation-protelis/src/test/kotlin/it/unibo/alchemist/model/protelis/TestGetPosition.kt b/alchemist-incarnation-protelis/src/test/kotlin/it/unibo/alchemist/model/protelis/TestGetPosition.kt index c66e703e7f..b11c409e1e 100644 --- a/alchemist-incarnation-protelis/src/test/kotlin/it/unibo/alchemist/model/protelis/TestGetPosition.kt +++ b/alchemist-incarnation-protelis/src/test/kotlin/it/unibo/alchemist/model/protelis/TestGetPosition.kt @@ -16,6 +16,7 @@ import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node.Companion.asProperty import it.unibo.alchemist.model.Time import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.incarnations.ProtelisIncarnation import it.unibo.alchemist.model.linkingrules.NoLinks import it.unibo.alchemist.model.positions.Euclidean2DPosition import it.unibo.alchemist.model.protelis.actions.RunProtelisProgram diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala index 8462a16c6a..766568214c 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala @@ -8,7 +8,6 @@ */ package it.unibo.alchemist.model.incarnations -import it.unibo.alchemist.model.implementations.nodes.ScafiDevice import it.unibo.alchemist.model.molecules.SimpleMolecule import it.unibo.alchemist.model.nodes.GenericNode import it.unibo.alchemist.model.reactions.{ChemicalReaction, Event} @@ -17,6 +16,7 @@ import it.unibo.alchemist.model.times.DoubleTime import it.unibo.alchemist.model._ import it.unibo.alchemist.model.scafi.actions.{RunScafiProgram, SendScafiMessage} import it.unibo.alchemist.model.scafi.conditions.ScafiComputationalRoundComplete +import it.unibo.alchemist.model.scafi.properties.ScafiDevice import it.unibo.alchemist.scala.ScalaInterpreter import org.apache.commons.math3.random.RandomGenerator @@ -26,6 +26,9 @@ import scala.collection.mutable.ListBuffer import scala.jdk.CollectionConverters._ sealed class ScafiIncarnation[T, P <: Position[P]] extends Incarnation[T, P] { + + import ScafiIncarnationUtils.runInScafiDeviceContext + private[this] def notNull[V](value: V, name: String = "Object"): V = Objects.requireNonNull(value, s"$name must not be null") diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/ScafiIncarnationForAlchemist.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/ScafiIncarnationForAlchemist.scala index 0ff8f615f3..2fd49719b3 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/ScafiIncarnationForAlchemist.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/ScafiIncarnationForAlchemist.scala @@ -12,8 +12,8 @@ import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.positions.Euclidean2DPosition import java.util.Optional -import it.unibo.alchemist.model.implementations.nodes.NodeManager import it.unibo.alchemist.model.molecules.SimpleMolecule +import it.unibo.alchemist.model.scafi.nodes.NodeManager import it.unibo.alchemist.model.times.DoubleTime import it.unibo.alchemist.model.{Environment, Layer} import it.unibo.scafi.incarnations.BasicAbstractIncarnation diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/RunScafiProgram.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/RunScafiProgram.scala index 616e0712b6..c40cfd6b4c 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/RunScafiProgram.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/RunScafiProgram.scala @@ -10,11 +10,11 @@ package it.unibo.alchemist.model.scafi.actions import it.unibo.alchemist.model.actions.AbstractLocalAction import it.unibo.alchemist.model.{Node, Position, Reaction} -import it.unibo.alchemist.model.implementations.nodes.SimpleNodeManager import it.unibo.alchemist.model.molecules.SimpleMolecule import it.unibo.alchemist.model.{Time => AlchemistTime, _} import it.unibo.alchemist.model.scafi.ScafiIncarnationForAlchemist import it.unibo.alchemist.model.scafi.ScafiIncarnationForAlchemist.{ContextImpl, _} +import it.unibo.alchemist.model.scafi.nodes.SimpleNodeManager import it.unibo.alchemist.scala.PimpMyAlchemist._ import it.unibo.scafi.space.Point3D import org.apache.commons.math3.random.RandomGenerator diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/SendScafiMessage.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/SendScafiMessage.scala index 6bc62051b8..77165e5827 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/SendScafiMessage.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/actions/SendScafiMessage.scala @@ -9,11 +9,12 @@ package it.unibo.alchemist.model.scafi.actions -import it.unibo.alchemist.model.{Node, Position, Reaction, ScafiIncarnationUtils} -import it.unibo.alchemist.model.ScafiIncarnationUtils._ -import it.unibo.alchemist.model.implementations.nodes.ScafiDevice +import it.unibo.alchemist.model.{Node, Position, Reaction} +import it.unibo.alchemist.model.incarnations.ScafiIncarnationUtils import it.unibo.alchemist.model._ import it.unibo.alchemist.model.actions.AbstractAction +import it.unibo.alchemist.model.incarnations.ScafiIncarnationUtils.runInScafiDeviceContext +import it.unibo.alchemist.model.scafi.properties.ScafiDevice import java.util.stream.Collectors import scala.jdk.CollectionConverters._ diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/conditions/ScafiComputationalRoundComplete.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/conditions/ScafiComputationalRoundComplete.scala index 05b14c5cac..3cb844bda4 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/conditions/ScafiComputationalRoundComplete.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/scafi/conditions/ScafiComputationalRoundComplete.scala @@ -8,10 +8,10 @@ */ package it.unibo.alchemist.model.scafi.conditions -import it.unibo.alchemist.model.ScafiIncarnationUtils import it.unibo.alchemist.model.conditions.AbstractCondition -import it.unibo.alchemist.model.implementations.nodes.ScafiDevice +import it.unibo.alchemist.model.incarnations.ScafiIncarnationUtils import it.unibo.alchemist.model.scafi.actions.RunScafiProgram +import it.unibo.alchemist.model.scafi.properties.ScafiDevice import it.unibo.alchemist.model.{Condition, Context, Node, Reaction} final class ScafiComputationalRoundComplete[T](val device: ScafiDevice[T], val program: RunScafiProgram[_, _]) diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/scala/PimpMyAlchemist.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/scala/PimpMyAlchemist.scala index 0ad20ff946..8f965b34bb 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/scala/PimpMyAlchemist.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/scala/PimpMyAlchemist.scala @@ -31,5 +31,5 @@ object PimpMyAlchemist { implicit def double2Time(time: Double): Time = new DoubleTime(time) implicit def molecule2String(molecule: Molecule): String = molecule.toString implicit def string2Molecule(str: String): Molecule = new SimpleMolecule(str) - implicit def function2CacheLoader[F, T](f: F => T) = new CacheLoader[F, T] { def load(key: F) = f(key) } + implicit def function2CacheLoader[F, T](f: F => T): CacheLoader[F, T] = new CacheLoader[F, T] { def load(key: F) = f(key) } } diff --git a/alchemist-kotlinscript/build.gradle.kts b/alchemist-kotlinscript/build.gradle.kts new file mode 100644 index 0000000000..adf5ea353a --- /dev/null +++ b/alchemist-kotlinscript/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("kotlin-jvm-convention") +} + +dependencies { + implementation(kotlin("script-runtime")) + implementation(kotlin("scripting-common")) + implementation(kotlin("scripting-jvm")) + implementation(kotlin("scripting-jvm-host")) +} diff --git a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt new file mode 100644 index 0000000000..1f877240ad --- /dev/null +++ b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.kotlinscript + +import kotlin.script.experimental.annotations.KotlinScript +import kotlin.script.experimental.api.ScriptAcceptedLocation +import kotlin.script.experimental.api.ScriptCompilationConfiguration +import kotlin.script.experimental.api.acceptedLocations +import kotlin.script.experimental.api.compilerOptions +import kotlin.script.experimental.api.defaultImports +import kotlin.script.experimental.api.ide +import kotlin.script.experimental.jvm.dependenciesFromClassContext +import kotlin.script.experimental.jvm.jvm + +/** + * Base interface for Alchemist Kotlin DSL scripts. + */ +@KotlinScript( + displayName = "Alchemist Kotlin DSL", + fileExtension = "alchemist.kts", + compilationConfiguration = AlchemistCompilationConfiguration::class, +) +interface AlchemistScript + +/** + * Compilation configuration for Alchemist scripts. + */ +object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ + defaultImports( + "it.unibo.alchemist.boundary.dsl.Dsl.simulation", + "it.unibo.alchemist.boundary.dsl.generated.*", + "it.unibo.alchemist.boundary.dsl.*", + "it.unibo.alchemist.boundary.dsl.Dsl.*", + "it.unibo.alchemist.model.*", + "it.unibo.alchemist.model.deployments.*", + "it.unibo.alchemist.model.incarnations.*", + "it.unibo.alchemist.model.actions.*", + "it.unibo.alchemist.model.conditions.*", + "it.unibo.alchemist.model.environments.*", + "it.unibo.alchemist.model.geometry.*", + "it.unibo.alchemist.model.layers.*", + "it.unibo.alchemist.model.linkingrules.*", + "it.unibo.alchemist.model.maps.actions.*", + "it.unibo.alchemist.model.maps.deployments.*", + "it.unibo.alchemist.model.maps.environments.*", + "it.unibo.alchemist.model.movestrategies.*", + "it.unibo.alchemist.model.neighborhoods.*", + "it.unibo.alchemist.model.nodes.*", + "it.unibo.alchemist.model.positions.*", + "it.unibo.alchemist.model.positionfilters.And", + "it.unibo.alchemist.model.positionfilters.Or", + "it.unibo.alchemist.model.positionfilters.Not", + "it.unibo.alchemist.model.positionfilters.Xor", + "it.unibo.alchemist.model.positionfilters.*", + "it.unibo.alchemist.model.properties.*", + "it.unibo.alchemist.model.routes.*", + "it.unibo.alchemist.model.reactions.*", + "it.unibo.alchemist.model.terminators.*", + "it.unibo.alchemist.model.timedistributions.*", + "it.unibo.alchemist.model.times.*", + "it.unibo.alchemist.boundary.properties.*", + "it.unibo.alchemist.boundary.dsl.aliases.*", + "it.unibo.alchemist.boundary.exporters.*", + "it.unibo.alchemist.boundary.extractors.*", + "it.unibo.alchemist.boundary.launchers.*", + "it.unibo.alchemist.boundary.statistic.*", + "it.unibo.alchemist.boundary.exportfilters.*", + "it.unibo.alchemist.boundary.variables.*", + "it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger", + ) + ide { + acceptedLocations(ScriptAcceptedLocation.Everywhere) + } + jvm { + dependenciesFromClassContext(AlchemistScript::class, wholeClasspath = true) + compilerOptions.append("-Xcontext-parameters") + } +}) { + // See: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/input.html + @Suppress("UnusedPrivateMember") + private fun readResolve(): Any = AlchemistCompilationConfiguration +} diff --git a/alchemist-kotlinscript/src/main/resources/META-INF/kotlin/script/templates/it.unibo.alchemist.kotlinscript.AlchemistScript b/alchemist-kotlinscript/src/main/resources/META-INF/kotlin/script/templates/it.unibo.alchemist.kotlinscript.AlchemistScript new file mode 100644 index 0000000000..e69de29bb2 diff --git a/alchemist-loading/build.gradle.kts b/alchemist-loading/build.gradle.kts index d457299f52..3cf55189d9 100644 --- a/alchemist-loading/build.gradle.kts +++ b/alchemist-loading/build.gradle.kts @@ -12,7 +12,6 @@ import Libs.incarnation plugins { id("kotlin-jvm-convention") - kotlin("plugin.scripting") } dependencies { @@ -23,10 +22,10 @@ dependencies { implementation(alchemist("engine")) implementation(alchemist("euclidean-geometry")) + implementation(alchemist("kotlinscript")) implementation(kotlin("reflect")) implementation(kotlin("script-runtime")) implementation(kotlin("scripting-common")) - implementation(kotlin("scripting-ide-services")) implementation(kotlin("scripting-jvm")) implementation(kotlin("scripting-jvm-host")) implementation(libs.apache.commons.lang3) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index c900669c6f..b40db9b63f 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -284,15 +284,15 @@ object DslLoaderFunctions { } } fun test12Layers(): Loader { - val incarnation = SAPEREIncarnation() + val incarnation = ProtelisIncarnation() return simulation(incarnation) { layer { molecule = "A" layer = StepLayer( 2.0, 2.0, - incarnation.createConcentration("100"), - incarnation.createConcentration("0"), + 100, + 0, ) } layer { @@ -300,8 +300,8 @@ object DslLoaderFunctions { layer = StepLayer( -2.0, -2.0, - incarnation.createConcentration("0"), - incarnation.createConcentration("100"), + 0, + 100, ) } deployments { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt index c240f4a031..ad9239286f 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt @@ -10,13 +10,18 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.LoadAlchemist -import java.io.File import java.nio.file.Files +import java.util.stream.Stream import kotlin.io.path.writeText import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import org.kaikikm.threadresloader.ResourceLoader class KotlinDslProviderTest { + @Test fun `a simple textual Kotlin DSL script should load`() { val script = """ @@ -34,42 +39,23 @@ class KotlinDslProviderTest { assertNotNull(loader) } - @Test - fun `loading the variables test from the Kotlin Script should provide the same value of the YAML file`() { - val dslUrl = requireNotNull(this.javaClass.getResource("/dsl/kts/15-variables.alchemist.kts")) { - "Resource /dsl/kts/15-variables.alchemist.kts not found on test classpath" - } - val dslFile = File(dslUrl.toURI()) - val dslLoader = { LoadAlchemist.from(dslFile) } - dslLoader.shouldEqual("dsl/yml/15-variables.yml") - } - - @Test - fun loadFromFile2() { - val dslUrl = requireNotNull(this.javaClass.getResource("/dsl/kts/14-exporters.alchemist.kts")) { - "Resource /dsl/kts/14-exporters.alchemist.kts not found on test classpath" - } - val dslFile = File(dslUrl.toURI()) - val dslLoader = { LoadAlchemist.from(dslFile) } - dslLoader.shouldEqual("dsl/yml/14-exporters.yml") - } - - @Test - fun loadFromFile3() { - val dslUrl = requireNotNull(this.javaClass.getResource("/dsl/kts/18-properties.alchemist.kts")) { - "Resource /dsl/kts/18-properties.alchemist.kts not found on test classpath" + @ParameterizedTest(name = "{0} should match {1}") + @MethodSource("equivalenceCases") + fun `Kotlin DSL resources should match YAML equivalents`(ktsResource: String, ymlResource: String) { + val url = requireNotNull(ResourceLoader.getResource(ktsResource)) { + "Resource $ktsResource not found on test classpath" } - val dslFile = File(dslUrl.toURI()) - val dslLoader = { LoadAlchemist.from(dslFile) } - dslLoader.shouldEqual("dsl/yml/18-properties.yml") + val loaderBuilder = { LoadAlchemist.from(url) } + loaderBuilder.shouldEqual(ymlResource) } - @Test - fun testUrlLoader() { - val dslUrl = requireNotNull(this.javaClass.getResource("/dsl/kts/12-layers.alchemist.kts")) { - "Resource /dsl/kts/12-layers.alchemist.kts not found on test classpath" - } - val dslLoader = { LoadAlchemist.from(dslUrl) } - dslLoader.shouldEqual("dsl/yml/12-layers.yml") + companion object { + @JvmStatic + fun equivalenceCases(): Stream = Stream.of( + Arguments.of("dsl/kts/12-layers.alchemist.kts", "dsl/yml/12-layers.yml"), + Arguments.of("dsl/kts/14-exporters.alchemist.kts", "dsl/yml/14-exporters.yml"), + Arguments.of("dsl/kts/15-variables.alchemist.kts", "dsl/yml/15-variables.yml"), + Arguments.of("dsl/kts/18-properties.alchemist.kts", "dsl/yml/18-properties.yml"), + ) } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt index b27f46c60d..e9c2e3a4d0 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt @@ -28,8 +28,8 @@ object LayerComparisonUtils { } } assertEquals( - dslDoubleValues, yamlDoubleValues, + dslDoubleValues, "Layer values at position $position should match", ) } diff --git a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts index 7c3e8116bd..f041194a6c 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts @@ -6,6 +6,8 @@ * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ + +package dsl.kts import another.location.SimpleMonitor import it.unibo.alchemist.boundary.dsl.Dsl.simulation diff --git a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts index 403660c284..18200544eb 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts @@ -6,18 +6,16 @@ * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ - -package dsl.kts - -val incarnation = SAPEREIncarnation() +import it.unibo.alchemist.model.sapere.ILsaMolecule +val incarnation: ProtelisIncarnation = ProtelisIncarnation() simulation(incarnation) { layer { molecule = "A" layer = StepLayer( 2.0, 2.0, - incarnation.createConcentration("100"), - incarnation.createConcentration("0"), + 100, + 0, ) } layer { @@ -25,8 +23,8 @@ simulation(incarnation) { layer = StepLayer( -2.0, -2.0, - incarnation.createConcentration("0"), - incarnation.createConcentration("100"), + 0, + 100, ) } deployments { diff --git a/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts index 703c8ee878..8879b07896 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts @@ -9,10 +9,7 @@ package dsl.kts -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation -import it.unibo.alchemist.boundary.dsl.Dsl.simulation - -val incarnation = PROTELIS.incarnation() +val incarnation = ProtelisIncarnation() simulation(incarnation) { exporter { type = CSVExporter( diff --git a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts index 60502f73f8..067e00fefb 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts @@ -9,6 +9,10 @@ package dsl.kts +import it.unibo.alchemist.model.sapere.ILsaMolecule +import it.unibo.alchemist.model.times.DoubleTime +import it.unibo.alchemist.model.positionfilters.Rectangle as InRectangle + simulation(SAPEREIncarnation()) { val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) @@ -31,7 +35,7 @@ simulation(SAPEREIncarnation()) { 0.1, ), ) { - inside(Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { + inside(InRectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { molecule = "token, 0, []" } programs { diff --git a/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts index 769afa7ca8..5807df56a3 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts @@ -9,11 +9,9 @@ package dsl.kts -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation -import it.unibo.alchemist.boundary.dsl.Dsl.simulation +import it.unibo.alchemist.model.positionfilters.Rectangle as InRectangle -val incarnation = SAPERE.incarnation() -simulation(incarnation) { +simulation(SAPEREIncarnation()) { deployments { deploy( circle( @@ -24,8 +22,8 @@ simulation(incarnation) { ), ) { properties { - val filter = RectangleFilter(-3.0, -3.0, 2.0, 2.0) - val filter2 = RectangleFilter(3.0, 3.0, 2.0, 2.0) + val filter = InRectangle(-3.0, -3.0, 2.0, 2.0) + val filter2 = InRectangle(3.0, 3.0, 2.0, 2.0) inside(filter) { +testNodeProperty("a") } diff --git a/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml b/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml index a54eb56c7c..e18d04c92f 100644 --- a/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml +++ b/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml @@ -1,4 +1,4 @@ -incarnation: sapere +incarnation: protelis environment: type: Continuous2DEnvironment diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 24c4ec1a0b..73686b8475 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -63,8 +63,9 @@ jpx = "io.jenetics:jpx:3.2.1" jsr305 = "com.google.code.findbugs:jsr305:3.0.2" junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } -junit-platform-engine = "org.junit.platform:junit-platform-engine:6.0.2" -junit-platform-launcher = "org.junit.platform:junit-platform-launcher:6.0.2" +junit-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" } +junit-platform-engine = { module = "org.junit.platform:junit-platform-engine", version.ref = "junit" } +junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit" } kasechange = "net.pearx.kasechange:kasechange:1.4.1" konf = { module = "com.uchuhimo:konf", version.ref = "konf" } korim = "com.soywiz.korlibs.korim:korim:4.0.10" @@ -156,6 +157,7 @@ scalacache = [ "scalacache-core", "scalacache-guava" ] scalatest = [ "scalatest", "scalatest-junit", "junit-platform-engine", "junit-platform-launcher" ] testing-compile = [ "junit-api", + "junit-params", "kotest-assertions-core", "kotest-assertions-table", "kotest-runner", diff --git a/settings.gradle.kts b/settings.gradle.kts index 45f1121e7b..c749707584 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,6 +27,7 @@ include( "alchemist-incarnation-sapere", "alchemist-incarnation-scafi", "alchemist-incarnation-biochemistry", + "alchemist-kotlinscript", "alchemist-loading", "alchemist-maintenance-tooling", "alchemist-maps", From d25bbb942cbbc19472c80979a0bc5c4e3da1f698 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 09:06:05 +0100 Subject: [PATCH 138/196] test: import missing class --- .../java/it/unibo/alchemist/model/protelis/TestIncarnation.java | 1 + 1 file changed, 1 insertion(+) diff --git a/alchemist-incarnation-protelis/src/test/java/it/unibo/alchemist/model/protelis/TestIncarnation.java b/alchemist-incarnation-protelis/src/test/java/it/unibo/alchemist/model/protelis/TestIncarnation.java index ba326ae221..091009b9da 100644 --- a/alchemist-incarnation-protelis/src/test/java/it/unibo/alchemist/model/protelis/TestIncarnation.java +++ b/alchemist-incarnation-protelis/src/test/java/it/unibo/alchemist/model/protelis/TestIncarnation.java @@ -16,6 +16,7 @@ import it.unibo.alchemist.model.Reaction; import it.unibo.alchemist.model.TimeDistribution; import it.unibo.alchemist.model.environments.Continuous2DEnvironment; +import it.unibo.alchemist.model.incarnations.ProtelisIncarnation; import it.unibo.alchemist.model.positions.Euclidean2DPosition; import it.unibo.alchemist.model.protelis.actions.SendToNeighbor; import it.unibo.alchemist.model.protelis.conditions.ComputationalRoundComplete; From 8216849d20dee927e9fffe0a86e2cbebc08782a0 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 10:53:27 +0100 Subject: [PATCH 139/196] build: consolidate Compose dependencies into a single bundle --- alchemist-composeui/build.gradle.kts | 6 +----- alchemist-test/build.gradle.kts | 2 -- gradle/libs.versions.toml | 6 ++++++ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/alchemist-composeui/build.gradle.kts b/alchemist-composeui/build.gradle.kts index 4fc6c69da1..a2f881b9ac 100644 --- a/alchemist-composeui/build.gradle.kts +++ b/alchemist-composeui/build.gradle.kts @@ -28,11 +28,7 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - implementation(compose.runtime) - implementation(compose.ui) - implementation(compose.foundation) - implementation(compose.material) - implementation(compose.components.resources) + implementation(libs.bundles.compose) } } } diff --git a/alchemist-test/build.gradle.kts b/alchemist-test/build.gradle.kts index a2d8b83b98..e473fd5898 100644 --- a/alchemist-test/build.gradle.kts +++ b/alchemist-test/build.gradle.kts @@ -11,7 +11,6 @@ import Libs.alchemist plugins { id("kotlin-jvm-convention") - alias(libs.plugins.ksp) } dependencies { @@ -24,7 +23,6 @@ dependencies { implementation(alchemist("implementationbase")) implementation(alchemist("physics")) runtimeOnly(libs.bundles.testing.runtimeOnly) - implementation(libs.ksp) } publishing.publications { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 73686b8475..f81de57a6b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,6 +37,11 @@ arrow-core = { module = "io.arrow-kt:arrow-core", version.ref = "arrow" } boilerplate = "org.danilopianini:boilerplate:0.2.2" caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.3" classgraph = "io.github.classgraph:classgraph:4.8.184" +compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose-multiplatform" } +compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-multiplatform" } +compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "compose-multiplatform" } +compose-material = { module = "org.jetbrains.compose.material:material", version.ref = "compose-multiplatform" } +compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "compose-multiplatform" } conrec = "org.danilopianini:conrec:0.1.1" dokka-gradle-plugin = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" } dyn4j = "org.dyn4j:dyn4j:5.0.2" @@ -136,6 +141,7 @@ svgsalamander = "guru.nidi.com.kitfox:svgSalamander:1.1.3" trove4j = "net.sf.trove4j:trove4j:3.0.3" [bundles] +compose = [ "compose-components-resources", "compose-foundation", "compose-material", "compose-runtime", "compose-ui" ] graphhopper = [ "graphhopper-core" ] graphql-server = [ "graphql-server", "graphql-server-ktor" ] kotlin-react = [ "kotlin-react", "kotlin-react-dom" ] From 6737cdaf66ff84354dc8972eb674d836d367005c Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 11:19:42 +0100 Subject: [PATCH 140/196] test(incarnation-scafi): update import path for ScafiIncarnation --- .../it/unibo/alchemist/scafi/test/TestScafiIncarnation.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-incarnation-scafi/src/test/scala/it/unibo/alchemist/scafi/test/TestScafiIncarnation.scala b/alchemist-incarnation-scafi/src/test/scala/it/unibo/alchemist/scafi/test/TestScafiIncarnation.scala index ff7b68d9fd..e7d44b713b 100644 --- a/alchemist-incarnation-scafi/src/test/scala/it/unibo/alchemist/scafi/test/TestScafiIncarnation.scala +++ b/alchemist-incarnation-scafi/src/test/scala/it/unibo/alchemist/scafi/test/TestScafiIncarnation.scala @@ -8,7 +8,7 @@ package it.unibo.alchemist.scafi.test -import it.unibo.alchemist.model.ScafiIncarnation +import it.unibo.alchemist.model.incarnations.ScafiIncarnation import it.unibo.alchemist.model.positions.Euclidean2DPosition import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.reactions.Event From 57ff74faeb9f5dcb8c434284d83d34d3ad1cfe6a Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 11:20:30 +0100 Subject: [PATCH 141/196] refactor: change AlchemistScript from abstract class to interface --- .../unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt index 030261aac2..7395db65fc 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt @@ -27,7 +27,7 @@ import kotlin.script.experimental.jvm.jvm fileExtension = "alchemist.kts", compilationConfiguration = AlchemistCompilationConfiguration::class, ) -abstract class AlchemistScript +interface AlchemistScript /** * Compilation configuration for Alchemist scripts. From fc10e59d053d1db7d1f6116257921e7d69a64ec2 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 11:58:33 +0100 Subject: [PATCH 142/196] test: add missing import for `SAPEREIncarnation` in `RegressionTest` --- .../kotlin/it/unibo/alchemist/model/sapere/RegressionTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/alchemist-incarnation-sapere/src/test/kotlin/it/unibo/alchemist/model/sapere/RegressionTest.kt b/alchemist-incarnation-sapere/src/test/kotlin/it/unibo/alchemist/model/sapere/RegressionTest.kt index 305b7109ef..fda9430d82 100644 --- a/alchemist-incarnation-sapere/src/test/kotlin/it/unibo/alchemist/model/sapere/RegressionTest.kt +++ b/alchemist-incarnation-sapere/src/test/kotlin/it/unibo/alchemist/model/sapere/RegressionTest.kt @@ -11,6 +11,7 @@ package it.unibo.alchemist.model.sapere import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.positions.Euclidean2DPosition import it.unibo.alchemist.model.sapere.nodes.LsaNode import it.unibo.alchemist.model.timedistributions.DiracComb From 9e4e1cf479ab702535b04b0d9d6db7c7badcebac Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 12:25:22 +0100 Subject: [PATCH 143/196] fix: fix broken subnetwork provisioning --- .../it/unibo/alchemist/util/Environments.kt | 29 ++++++++-------- .../unibo/alchemist/util/TestDiameterUtils.kt | 34 +++++++++---------- .../util/TestEnvironmentsDiameter.kt | 7 ++-- ...TestEnvironmentsDiameterWithHopDistance.kt | 13 ++++--- 4 files changed, 44 insertions(+), 39 deletions(-) diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/util/Environments.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/util/Environments.kt index 1ed481d1ec..addbb219e4 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/util/Environments.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/util/Environments.kt @@ -40,12 +40,12 @@ object Environments { /** * Computes the diameter of all subnetworks in the environment. - * The diameter is the longest shortest path between any two nodes, - * evaluated using the [allShortestHopPaths] method. - * Returns a [Set] containing the subnetworks. + * The diameter is the longest shortest path between any two nodes. + * Returns a [Map] containing the subnetwork related to each [Node] of the environment. */ - fun Environment.allSubNetworksByNodeWithHopDistance(): Map, Network> = - allSubNetworksByNode(hopDistance()) + fun Environment.allSubNetworks( + computeDistance: (Node, Node) -> Double = environmentMetricDistance(), + ): Set> = allSubNetworksByNode(computeDistance).values.toSet() /** * Computes the diameter of all subnetworks in the environment. @@ -53,13 +53,13 @@ object Environments { * evaluated using the [allShortestHopPaths] method. * Returns a [Set] containing the subnetworks. */ - fun Environment.allSubNetworksWithHopDistance(): Set> = - allSubNetworksByNodeWithHopDistance().values.toSet() + fun Environment.allSubNetworksByNodeWithHopDistance(): Map, Network> = + allSubNetworksByNode(hopDistance()) /** * Computes the diameter of all subnetworks in the environment. * The diameter is the longest shortest path between any two nodes. - * Returns a [Set] containing the subnetworks. + * Returns a [Map] mapping each node to the subnetwork it belongs to. */ fun Environment.allSubNetworksByNode( computeDistance: (Node, Node) -> Double = environmentMetricDistance(), @@ -72,7 +72,7 @@ object Environments { when (val subnetwork = subnetworks[centerIndex]) { null -> { val newSubnetwork = MutableNetwork(0.0, mutableListOf(centerNode)) - result.put(centerNode, newSubnetwork) + result[centerNode] = newSubnetwork val centerRow = paths.row(centerIndex) for (potentialNeighborIndex in centerIndex + 1 until nodeCount) { val distanceToNeighbor = centerRow[potentialNeighborIndex] @@ -93,6 +93,7 @@ object Environments { .maxOrNull() ?: 0.0, ) + result[centerNode] = subnetwork } } } @@ -101,12 +102,12 @@ object Environments { /** * Computes the diameter of all subnetworks in the environment. - * The diameter is the longest shortest path between any two nodes. - * Returns a [Map] containing the subnetwork related to each [Node] of the environment. + * The diameter is the longest shortest path between any two nodes, + * evaluated using the [allShortestHopPaths] method. + * Returns a [Set] containing the subnetworks. */ - fun Environment.allSubNetworks( - computeDistance: (Node, Node) -> Double = environmentMetricDistance(), - ): Set> = allSubNetworksByNode(computeDistance).values.toSet() + fun Environment.allSubNetworksWithHopDistance(): Set> = + allSubNetworksByNodeWithHopDistance().values.toSet() /** * Calculates the shortest paths using the Floyd-Warshall algorithm calculating the Hop Distance between nodes. diff --git a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt index 4d56c5465f..1517ea594b 100644 --- a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt +++ b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt @@ -103,33 +103,33 @@ val twoConnectedNodesAndOneIsolated = environmentWithNodesAt(ORIGIN, 3.0 to 0.0, */ val twoSubnetworksWithTwoNodesEach = environmentWithNodesAt(ORIGIN, 3.0 to 0.0, 10.0 to 0.0, 10.0 to 3.0) -/** - * Represents a network composed of two subnetworks, - * each with different amount of nodes. - */ -val twoSparseSubnetworks = environmentWithNodesAt( +private val subnetwork1 = listOf( + -3.0 to 3.0, ORIGIN, - 12.0 to 12.0, 0.0 to 6.0, + 3.0 to 3.0, +).toTypedArray() + +private val subnetwork2 = listOf( + 12.0 to 12.0, 12.0 to 14.0, - -3.0 to 3.0, 9.0 to 15.0, - 3.0 to 3.0, 15.0 to 15.0, -) +).toTypedArray() + +/** + * Represents a network composed of two subnetworks, + * each with different amount of nodes. + */ +val twoSparseSubnetworks = environmentWithNodesAt(*subnetwork1, *subnetwork2) /** * Represents a network composed of three subnetworks, * each with different amount of nodes. */ val threeSparseSubnetworks = environmentWithNodesAt( - ORIGIN, - 12.0 to 12.0, - 0.0 to 6.0, - 12.0 to 14.0, - -3.0 to 3.0, - 9.0 to 15.0, - 3.0 to 3.0, - 15.0 to 15.0, + *subnetwork1, + *subnetwork2, + // Isolated node 25.0 to 25.0, ) diff --git a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt index d5b61d1be8..a2112024bb 100644 --- a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt +++ b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt @@ -10,6 +10,7 @@ package it.unibo.alchemist.util import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.util.Environments.allSubNetworks import it.unibo.alchemist.util.Environments.allSubNetworksByNode import it.unibo.alchemist.util.Environments.isNetworkSegmented import java.math.BigDecimal @@ -24,9 +25,9 @@ object TestEnvironmentsDiameter { private infix fun Environment.mustNotBeSegmentedAndHaveDiameter(expected: Double) { assertFalse(isNetworkSegmented()) - assertEquals( + assertEquals( expected, - allSubNetworksByNode().values.single().diameter.roundToTwoDecimals(), + allSubNetworks().single().diameter.roundToTwoDecimals(), ) } @@ -34,7 +35,7 @@ object TestEnvironmentsDiameter { require(index < nodes.size) val diameter = allSubNetworksByNode()[nodes[index]]?.diameter if (diameter != null) { - assertEquals( + assertEquals( expected, diameter.roundToTwoDecimals(), ) diff --git a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameterWithHopDistance.kt b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameterWithHopDistance.kt index 58ca8d3cc3..179b0970a5 100644 --- a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameterWithHopDistance.kt +++ b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameterWithHopDistance.kt @@ -26,7 +26,8 @@ object TestEnvironmentsDiameterWithHopDistance { expected: Double, ) { require(index < nodes.size) - assertEquals(expected, allSubNetworksByNodeWithHopDistance()[nodes[index]]?.diameter!!) + val subnetworkOfIndexedNode = checkNotNull(allSubNetworksByNodeWithHopDistance()[nodes[index]]) + assertEquals(expected, subnetworkOfIndexedNode.diameter) } private infix fun Environment.mustNotBeSegmentedAndHaveHopDiameter(expected: Double) { @@ -91,8 +92,9 @@ object TestEnvironmentsDiameterWithHopDistance { with(twoSparseSubnetworks) { mustBeSegmented() withHopDistanceMustHave(2.subnetworks()) - specificNodeInASegmentedNetworkShouldHaveHopDiameter(0, 2.0) - specificNodeInASegmentedNetworkShouldHaveHopDiameter(1, 1.0) + nodes.forEach { + specificNodeInASegmentedNetworkShouldHaveHopDiameter(it.id, 2.0) + } } } @@ -101,8 +103,9 @@ object TestEnvironmentsDiameterWithHopDistance { with(threeSparseSubnetworks) { mustBeSegmented() withHopDistanceMustHave(3.subnetworks()) - specificNodeInASegmentedNetworkShouldHaveHopDiameter(0, 2.0) - specificNodeInASegmentedNetworkShouldHaveHopDiameter(1, 1.0) + (0 until nodeCount - 1).forEach { + specificNodeInASegmentedNetworkShouldHaveHopDiameter(it, 2.0) + } specificNodeInASegmentedNetworkShouldHaveHopDiameter(nodeCount - 1, 0.0) } } From d8c4080f03935d120c4d7151be071d622a803fde Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 15:51:41 +0100 Subject: [PATCH 144/196] test: add missing import for `SAPEREIncarnation` in `TestIncarnation` --- .../java/it/unibo/alchemist/model/sapere/TestIncarnation.java | 1 + 1 file changed, 1 insertion(+) diff --git a/alchemist-incarnation-sapere/src/test/java/it/unibo/alchemist/model/sapere/TestIncarnation.java b/alchemist-incarnation-sapere/src/test/java/it/unibo/alchemist/model/sapere/TestIncarnation.java index 1a8e7a75c9..780c055535 100644 --- a/alchemist-incarnation-sapere/src/test/java/it/unibo/alchemist/model/sapere/TestIncarnation.java +++ b/alchemist-incarnation-sapere/src/test/java/it/unibo/alchemist/model/sapere/TestIncarnation.java @@ -13,6 +13,7 @@ import it.unibo.alchemist.model.Reaction; import it.unibo.alchemist.model.TimeDistribution; import it.unibo.alchemist.model.environments.Continuous2DEnvironment; +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation; import it.unibo.alchemist.model.positions.Euclidean2DPosition; import it.unibo.alchemist.model.sapere.actions.LsaAllNeighborsAction; import it.unibo.alchemist.model.sapere.actions.LsaRandomNeighborAction; From ae251e3858e6136eab1370aa6dd6a2970087af66 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 15:52:27 +0100 Subject: [PATCH 145/196] test: simplify variables testing --- .../it/unibo/alchemist/dsl/TestVariables.kt | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt index 767358056b..da4ea6fca7 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -17,7 +17,10 @@ import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.deployments.point +import it.unibo.alchemist.model.incarnations.ProtelisIncarnation import it.unibo.alchemist.model.incarnations.SAPEREIncarnation +import it.unibo.alchemist.model.molecules.SimpleMolecule import it.unibo.alchemist.model.sapere.molecules.LsaMolecule import org.junit.jupiter.api.Test @@ -62,22 +65,39 @@ class TestVariables { @Test fun

> testDependendVariable() { - val loader = simulation(SAPEREIncarnation()) { - val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) - val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + val loader = simulation(ProtelisIncarnation()) { + val geometricVariable: Double by variable(GeometricVariable(10.0, 1.0, 1000.0, 4)) + val linearVariable: Double by variable(LinearVariable(1.0, 1.0, 2.0, 3.0)) - val mSize by variable { -size } - val sourceStart by variable { mSize / 10.0 } - val sourceSize by variable { size / 5.0 } + val mSize by variable { -linearVariable } + val sourceStart by variable { mSize / geometricVariable } + val sourceSize by variable { linearVariable / 5.0 } - runLater { - rate.shouldBe(2.0) - size.shouldBe(10.0) - mSize.shouldBe(-10.0) - sourceStart.shouldBe(-1.0) - sourceSize.shouldBe(2.0) + deployments { + deploy(point(0.0, 0.0)) { + all { + molecule = "mSize" + concentration = mSize + } + all { + molecule = "sourceStart" + concentration = sourceStart + } + all { + molecule = "sourceSize" + concentration = sourceSize + } + } } } - loader.getWith, P>(mapOf("size" to 10.0)) + loader.variables.size shouldBe 2 + loader.dependentVariables.size shouldBe 0 + loader.getWith, P>(mapOf("linearVariable" to 10.0)).apply { + environment.nodes.size shouldBe 1 + val node = environment.nodes.single() + node.getConcentration(SimpleMolecule("mSize")) shouldBe -10.0 + node.getConcentration(SimpleMolecule("sourceStart")) shouldBe -1.0 + node.getConcentration(SimpleMolecule("sourceSize")) shouldBe 2.0 + } } } From 092f0b2905afc754e250a0bd9378402c4443c8d7 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 16:05:31 +0100 Subject: [PATCH 146/196] test: correct import for `SAPEREIncarnation` in `LsaNodeConcurrencyTest` --- .../alchemist/model/sapere/nodes/LsaNodeConcurrencyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-incarnation-sapere/src/test/java/it/unibo/alchemist/model/sapere/nodes/LsaNodeConcurrencyTest.java b/alchemist-incarnation-sapere/src/test/java/it/unibo/alchemist/model/sapere/nodes/LsaNodeConcurrencyTest.java index 3a9bbe5b6c..3625454a18 100644 --- a/alchemist-incarnation-sapere/src/test/java/it/unibo/alchemist/model/sapere/nodes/LsaNodeConcurrencyTest.java +++ b/alchemist-incarnation-sapere/src/test/java/it/unibo/alchemist/model/sapere/nodes/LsaNodeConcurrencyTest.java @@ -11,8 +11,8 @@ import it.unibo.alchemist.model.Environment; import it.unibo.alchemist.model.Molecule; +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation; import it.unibo.alchemist.model.sapere.ILsaMolecule; -import it.unibo.alchemist.model.sapere.SAPEREIncarnation; import it.unibo.alchemist.model.sapere.molecules.LsaMolecule; import it.unibo.alchemist.model.environments.Continuous2DEnvironment; import it.unibo.alchemist.model.positions.Euclidean2DPosition; From 0162b30a7caefe20d5c326b0d0fb80bd26361742 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 16:06:44 +0100 Subject: [PATCH 147/196] fix: update assertion to use `allSubNetworks()` in `TestEnvironmentsDiameter` --- .../kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt index a2112024bb..f36c380233 100644 --- a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt +++ b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt @@ -21,7 +21,7 @@ import org.junit.jupiter.api.Test object TestEnvironmentsDiameter { private infix fun Environment.mustHave(expected: Subnetworks) = - assertEquals(expected.count, allSubNetworksByNode().size) + assertEquals(expected.count, allSubNetworks().size) private infix fun Environment.mustNotBeSegmentedAndHaveDiameter(expected: Double) { assertFalse(isNetworkSegmented()) From f97e50d73ca731699995ccc0d9987c9d8cfaf833 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 18:43:15 +0100 Subject: [PATCH 148/196] chore: move copyright header --- alchemist-composeui/build.gradle.kts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alchemist-composeui/build.gradle.kts b/alchemist-composeui/build.gradle.kts index a2f881b9ac..3730e4122f 100644 --- a/alchemist-composeui/build.gradle.kts +++ b/alchemist-composeui/build.gradle.kts @@ -1,7 +1,3 @@ -import it.unibo.alchemist.build.devServer -import it.unibo.alchemist.build.webCommonConfiguration -import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl - /* * Copyright (C) 2010-2025, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. @@ -11,6 +7,10 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl * as described in the file LICENSE in the Alchemist distribution's top directory. */ +import it.unibo.alchemist.build.devServer +import it.unibo.alchemist.build.webCommonConfiguration +import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl + plugins { id("kotlin-multiplatform-convention") alias(libs.plugins.compose.multiplatform) From bfbb6fa25dfaafe76722dc91733326248e152263 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 26 Jan 2026 18:51:24 +0100 Subject: [PATCH 149/196] test: update diameter assertions to use dynamic subnetwork size --- .../test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt | 2 +- .../it/unibo/alchemist/util/TestEnvironmentsDiameter.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt index 1517ea594b..14a8a52afa 100644 --- a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt +++ b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestDiameterUtils.kt @@ -103,7 +103,7 @@ val twoConnectedNodesAndOneIsolated = environmentWithNodesAt(ORIGIN, 3.0 to 0.0, */ val twoSubnetworksWithTwoNodesEach = environmentWithNodesAt(ORIGIN, 3.0 to 0.0, 10.0 to 0.0, 10.0 to 3.0) -private val subnetwork1 = listOf( +val subnetwork1 = listOf( -3.0 to 3.0, ORIGIN, 0.0 to 6.0, diff --git a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt index f36c380233..6d0611d34d 100644 --- a/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt +++ b/alchemist-implementationbase/src/test/kotlin/it/unibo/alchemist/util/TestEnvironmentsDiameter.kt @@ -100,7 +100,7 @@ object TestEnvironmentsDiameter { mustBeSegmented() mustHave(2.subnetworks()) specificNodeInASegmentedNetworkShouldHaveDiameter(0, 8.49) - specificNodeInASegmentedNetworkShouldHaveDiameter(1, 6.32) + specificNodeInASegmentedNetworkShouldHaveDiameter(subnetwork1.size + 1, 6.32) } } @@ -110,7 +110,7 @@ object TestEnvironmentsDiameter { mustBeSegmented() mustHave(3.subnetworks()) specificNodeInASegmentedNetworkShouldHaveDiameter(0, 8.49) - specificNodeInASegmentedNetworkShouldHaveDiameter(1, 6.32) + specificNodeInASegmentedNetworkShouldHaveDiameter(subnetwork1.size + 1, 6.32) specificNodeInASegmentedNetworkShouldHaveDiameter(nodeCount - 1, 0.0) } } From e62ed4a957d37803c8cfab2add64c2350cf73ffc Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Tue, 27 Jan 2026 13:16:37 +0100 Subject: [PATCH 150/196] refactor: remove unused random generator and update deployment context --- .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 2 +- .../boundary/dsl/model/DeploymentsContext.kt | 11 +-- .../dsl/model/DeploymentsContextImpl.kt | 83 ++++++++-------- .../boundary/dsl/model/SimulationContext.kt | 2 +- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 96 +++++-------------- .../alchemist/dsl/RuntimeComparisonHelper.kt | 3 - .../it/unibo/alchemist/dsl/TestDeployments.kt | 5 +- 7 files changed, 71 insertions(+), 131 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index 056a683c04..b9dd80963d 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -77,7 +77,7 @@ object Dsl { ): Loader { val ctx = SimulationContextImpl(incarnation, environmentFactory) ctx.apply { - context(incarnation, ctx.simulationGenerator, ctx.environment) { + context(incarnation, ctx.scenarioGenerator, ctx.environment) { block() } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index 13e51818e4..8e29369669 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -55,15 +55,6 @@ interface DeploymentsContext> { */ val ctx: SimulationContext - /** - * The random number generator for scenario generation. - * - * Used for random deployments and position perturbations. - * - * @see [org.apache.commons.math3.random.RandomGenerator] - */ - val generator: RandomGenerator - /** * Deploys nodes using a deployment with a configuration block. * @@ -80,7 +71,7 @@ interface DeploymentsContext> { * @see [it.unibo.alchemist.model.Deployment] */ // TODO: fix the doc - context(randomGenerator: RandomGenerator, environment: Environment) + context(environment: Environment) fun deploy( deployment: Deployment

, nodeFactory: context(RandomGenerator, Environment) () -> Node = { diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt index 6ae77fc7cf..7c3baf269e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt @@ -30,55 +30,54 @@ import org.apache.commons.math3.random.RandomGenerator open class DeploymentsContextImpl>(override val ctx: SimulationContext) : DeploymentsContext { - override val generator: RandomGenerator - get() = ctx.scenarioGenerator - - context(randomGenerator: RandomGenerator, environment: Environment) + context(environment: Environment) override fun deploy( deployment: Deployment

, nodeFactory: context(RandomGenerator, Environment) () -> Node, block: context(Environment, Node) DeploymentContext.() -> Unit, ) { - logger.debug("Deploying deployment: {}", deployment) - // Additional linking rules - deployment.getAssociatedLinkingRule()?.let { newLinkingRule -> - val composedLinkingRule = - when (val linkingRule = ctx.environment.linkingRule) { - is NoLinks -> newLinkingRule - is CombinedLinkingRule -> CombinedLinkingRule(linkingRule.subRules + listOf(newLinkingRule)) - else -> CombinedLinkingRule(listOf(linkingRule, newLinkingRule)) - } - ctx.environment.linkingRule = composedLinkingRule - } - deployment.forEach { position -> - logger.debug("visiting position: {} for deployment: {}", position, deployment) - logger.debug("creaing node for deployment: {}", deployment) - val node = nodeFactory() - context(node) { - // load properties - val deploymentContext = DeploymentContextImpl(deployment).apply { block() } - deploymentContext.propertiesContext.applyToNode(node, position) - // load contents - val contents = deploymentContext.contents - for (content in contents) { - deploymentContext.applyToNodes(node, position, content) - } - // load programs - val programs = deploymentContext.programsContext.programs - val createdPrograms = mutableListOf?, Actionable>>() - for (programEntry in programs) { - val pp = deploymentContext.programsContext.applyToNodes( - node, - position, - programEntry.program, - programEntry.filter, - ) - createdPrograms.add(pp) + context(ctx.simulationGenerator) { + logger.debug("Deploying deployment: {}", deployment) + // Additional linking rules + deployment.getAssociatedLinkingRule()?.let { newLinkingRule -> + val composedLinkingRule = + when (val linkingRule = ctx.environment.linkingRule) { + is NoLinks -> newLinkingRule + is CombinedLinkingRule -> CombinedLinkingRule(linkingRule.subRules + listOf(newLinkingRule)) + else -> CombinedLinkingRule(listOf(linkingRule, newLinkingRule)) + } + ctx.environment.linkingRule = composedLinkingRule + } + deployment.forEach { position -> + logger.debug("visiting position: {} for deployment: {}", position, deployment) + logger.debug("creaing node for deployment: {}", deployment) + val node = nodeFactory() + context(node) { + // load properties + val deploymentContext = DeploymentContextImpl(deployment).apply { block() } + deploymentContext.propertiesContext.applyToNode(node, position) + // load contents + val contents = deploymentContext.contents + for (content in contents) { + deploymentContext.applyToNodes(node, position, content) + } + // load programs + val programs = deploymentContext.programsContext.programs + val createdPrograms = mutableListOf?, Actionable>>() + for (programEntry in programs) { + val pp = deploymentContext.programsContext.applyToNodes( + node, + position, + programEntry.program, + programEntry.filter, + ) + createdPrograms.add(pp) + } + logger.debug("programs={}", createdPrograms) + logger.debug("Adding node to environment at position: {}", position) } - logger.debug("programs={}", createdPrograms) - logger.debug("Adding node to environment at position: {}", position) + ctx.environment.addNode(node, position) } - ctx.environment.addNode(node, position) } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 4c00366344..efc42760ea 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -118,7 +118,7 @@ interface SimulationContext> { /** * Adds a termination predicate to the simulation. * - * @param terminator The termination predicate to add + * @param block The termination predicate to add * @see [TerminationPredicate] */ fun terminators(block: TerminatorsContext.() -> Unit) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index b40db9b63f..f828fba517 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -20,6 +20,7 @@ import it.unibo.alchemist.boundary.properties.testNodeProperty import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.actions.brownianMove @@ -49,9 +50,12 @@ import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.timedistributions.DiracComb import it.unibo.alchemist.model.timedistributions.ExponentialTime import it.unibo.alchemist.model.timedistributions.WeibullTime +import it.unibo.alchemist.model.timedistributions.exponentialTime +import it.unibo.alchemist.model.timedistributions.weibullTime import it.unibo.alchemist.model.times.DoubleTime import it.unibo.alchemist.test.globalTestReaction import org.apache.commons.math3.random.MersenneTwister +import org.apache.commons.math3.random.RandomGenerator object DslLoaderFunctions { fun test01Nodes(): Loader { @@ -73,9 +77,7 @@ object DslLoaderFunctions { networkModel = ConnectWithinDistance(0.5) deployments { deploy( - Circle( - ctx.environment, - generator, + circle( 10, 0.0, 0.0, @@ -104,24 +106,25 @@ object DslLoaderFunctions { } } } + context(_: RandomGenerator, _: Environment<*, Euclidean2DPosition>) + fun makePerturbedGridForTesting() = grid( + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.25, + 0.1, + 0.1, + ) fun test05Content(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { val hello = "hello" - deploy( - grid( - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, - 0.25, - 0.1, - 0.1, - ), - ) { + deploy(makePerturbedGridForTesting()) + { all { molecule = hello } @@ -135,16 +138,7 @@ object DslLoaderFunctions { networkModel = ConnectWithinDistance(0.5) deployments { val hello = "hello" - deploy( - Grid( - ctx.environment, generator, - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, 0.25, 0.1, 0.1, - ), - ) { + deploy(makePerturbedGridForTesting()) { all { molecule = hello } @@ -162,18 +156,7 @@ object DslLoaderFunctions { networkModel = ConnectWithinDistance(0.5) deployments { val token = "token" - deploy( - grid( - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, - 0.25, - 0.1, - 0.1, - ), - ) { + deploy(makePerturbedGridForTesting()) { inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { molecule = token } @@ -196,16 +179,12 @@ object DslLoaderFunctions { programs { all { timeDistribution = +JaktaTimeDistribution( - sense = WeibullTime( + sense = weibullTime( 1.0, 1.0, - ctx.ctx.ctx.generator, ), deliberate = DiracComb(0.1), - act = ExponentialTime( - 1.0, - ctx.ctx.ctx.generator, - ), + act = exponentialTime(1.0), ) program = "1 + 1" } @@ -218,12 +197,7 @@ object DslLoaderFunctions { return simulation(incarnation) { networkModel = ConnectWithinDistance(0.5) deployments { - deploy( - Grid( - ctx.environment, generator, - -5.0, -5.0, 5.0, 5.0, 0.25, 0.25, 0.1, 0.1, - ), - ) { + deploy(makePerturbedGridForTesting()) { inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { molecule = "token, 0, []" } @@ -355,18 +329,7 @@ object DslLoaderFunctions { terminators { +AfterTime, Euclidean2DPosition>(DoubleTime(1.0)) } networkModel = ConnectWithinDistance(0.5) deployments { - deploy( - grid( - mSize, - mSize, - size, - size, - 0.25, - 0.25, - 0.1, - 0.1, - ), - ) { + deploy(makePerturbedGridForTesting()) { inside(Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { molecule = "token, 0, []" } @@ -389,16 +352,7 @@ object DslLoaderFunctions { networkModel = ConnectWithinDistance(0.5) deployments { val token = "token" - deploy( - Grid( - ctx.environment, generator, - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, 0.25, 0.1, 0.1, - ), - ) { + deploy(makePerturbedGridForTesting()) { inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { molecule = token } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt index f99eacdd73..4b9d051771 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt @@ -408,16 +408,13 @@ object RuntimeComparisonHelper { positionTolerance: Double = 1e-6, ) { println("Comparing runtime node states... (position tolerance: $positionTolerance)") - val dslNodesWithPos = dslEnv.nodes.map { it to dslEnv.getPosition(it) } val yamlNodesWithPos = yamlEnv.nodes.map { it to yamlEnv.getPosition(it) }.toMutableList() - val (matchedPairs, unmatchedDslNodes, distances) = matchNodesByPosition( dslNodesWithPos, yamlNodesWithPos, positionTolerance, ) - printMatchingStatistics(distances, matchedPairs, dslNodesWithPos.size) checkUnmatchedNodes(unmatchedDslNodes, yamlNodesWithPos, distances, positionTolerance) compareMatchedNodes(matchedPairs, dslEnv, yamlEnv, positionTolerance) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index 8f5fa51817..40f2109c4e 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -12,6 +12,7 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.deployments.grid import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import org.junit.jupiter.api.Test @@ -46,9 +47,7 @@ class TestDeployments { fun testGridDeployment() { val loader = simulation(SAPEREIncarnation()) { deployments { - val grid = Grid( - ctx.environment, - generator, + val grid = grid( 1.0, 1.0, 5.0, From 9351dadbcaba967f17f777dd9a835df7ca005b53 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Tue, 27 Jan 2026 19:11:48 +0100 Subject: [PATCH 151/196] refactor: remove unused time distribution parameters and simplify simulation context --- .../it/unibo/alchemist/model/Incarnation.java | 6 - .../biochemistry/BiochemistryIncarnation.java | 2 - .../model/incarnations/ProtelisIncarnation.kt | 6 +- .../model/incarnations/SAPEREIncarnation.java | 6 +- .../boundary/dsl/model/ProgramContext.kt | 144 ++++++++++++++++++ .../boundary/dsl/model/ProgramsContext.kt | 115 -------------- .../boundary/dsl/model/ProgramsContextImpl.kt | 27 ---- .../boundary/dsl/model/SeedsContext.kt | 46 ++++++ .../boundary/dsl/model/SimulationContext.kt | 2 + .../dsl/model/SimulationContextImpl.kt | 25 +++ .../boundary/loader/SimulationModel.kt | 4 +- .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 2 +- .../alchemist/dsl/RuntimeComparisonHelper.kt | 56 ++----- .../it/unibo/alchemist/dsl/TestComparators.kt | 21 +-- .../JaktaTimeDistribution.kt | 14 +- .../dsl/kts/19-performance.alchemist.kts | 4 +- 16 files changed, 246 insertions(+), 234 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SeedsContext.kt diff --git a/alchemist-api/src/main/java/it/unibo/alchemist/model/Incarnation.java b/alchemist-api/src/main/java/it/unibo/alchemist/model/Incarnation.java index e137564fbd..b9bcbcc2fb 100644 --- a/alchemist-api/src/main/java/it/unibo/alchemist/model/Incarnation.java +++ b/alchemist-api/src/main/java/it/unibo/alchemist/model/Incarnation.java @@ -119,8 +119,6 @@ Reaction createReaction( * @param node * the node that will host this object. If it is `null` the actionable * will not belong to a {@link Node} - * @param time - * the time distribution of the reaction * @param actionable * the actionable hosting this object * @param additionalParameters @@ -131,7 +129,6 @@ Condition createCondition( RandomGenerator randomGenerator, Environment environment, @Nullable Node node, - TimeDistribution time, Actionable actionable, @Nullable Object additionalParameters ); @@ -144,8 +141,6 @@ Condition createCondition( * @param node * the node that will host this object. If it is `null` the actionable * will not belong to a {@link Node} - * @param time - * the time distribution of the reaction * @param actionable * the actionable hosting this object * @param additionalParameters @@ -156,7 +151,6 @@ Action createAction( RandomGenerator randomGenerator, Environment environment, @Nullable Node node, - TimeDistribution time, Actionable actionable, @Nullable Object additionalParameters ); diff --git a/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/BiochemistryIncarnation.java b/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/BiochemistryIncarnation.java index 4e09ffaf56..48de22ded8 100644 --- a/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/BiochemistryIncarnation.java +++ b/alchemist-incarnation-biochemistry/src/main/java/it/unibo/alchemist/model/biochemistry/BiochemistryIncarnation.java @@ -108,7 +108,6 @@ public Condition createCondition( final RandomGenerator randomGenerator, final Environment environment, final Node node, - final TimeDistribution time, final Actionable actionable, final @Nullable Object additionalParameters ) { @@ -120,7 +119,6 @@ public Action createAction( final RandomGenerator randomGenerator, final Environment environment, final Node node, - final TimeDistribution time, final Actionable actionable, final @Nullable Object additionalParameters ) { diff --git a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt index 8fc639544d..c51405159f 100644 --- a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt +++ b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt @@ -77,7 +77,6 @@ class ProtelisIncarnation

> : Incarnation { randomGenerator: RandomGenerator, environment: Environment, node: Node?, - time: TimeDistribution, actionable: Actionable, additionalParameters: Any?, ): Action { @@ -135,7 +134,6 @@ class ProtelisIncarnation

> : Incarnation { randomGenerator: RandomGenerator, environment: Environment, node: Node?, - time: TimeDistribution, actionable: Actionable, additionalParameters: Any?, ): Condition { @@ -203,11 +201,11 @@ class ProtelisIncarnation

> : Incarnation { } parameter?.let { result.actions = - listOf(createAction(randomGenerator, environment, node, timeDistribution, result, it)) + listOf(createAction(randomGenerator, environment, node, result, it)) } if (isSend) { result.conditions = - listOf(createCondition(randomGenerator, environment, node, timeDistribution, result, null)) + listOf(createCondition(randomGenerator, environment, node, result, null)) } return result } diff --git a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java index 43c8489738..41a7b614f3 100644 --- a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java +++ b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java @@ -206,7 +206,7 @@ public Reaction> createReaction( final Matcher condMatcher = MATCH_CONDITION.matcher(conditionsSpec); while (condMatcher.find()) { final String condition = condMatcher.group(CONDITION_GROUP); - conditions.add(createCondition(randomGenerator, environment, node, timeDistribution, result, condition)); + conditions.add(createCondition(randomGenerator, environment, node, result, condition)); } } else { illegalSpec( @@ -221,7 +221,7 @@ public Reaction> createReaction( final Matcher actMatcher = MATCH_ACTION.matcher(actionsSpec); while (actMatcher.find()) { final String action = actMatcher.group(ACTION_GROUP); - actions.add(createAction(randomGenerator, environment, node, timeDistribution, result, action)); + actions.add(createAction(randomGenerator, environment, node, result, action)); } } else { illegalSpec("not a sequence of valid conditions" @@ -248,7 +248,6 @@ public Condition> createCondition( final RandomGenerator randomGenerator, final Environment, P> environment, final Node> node, - final TimeDistribution> time, final Actionable> reaction, final @Nullable Object additionalParameters ) { @@ -268,7 +267,6 @@ public Action> createAction( final RandomGenerator randomGenerator, final Environment, P> environment, final Node> node, - final TimeDistribution> time, final Actionable> actionable, final @Nullable Object additionalParameters ) { diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt new file mode 100644 index 0000000000..eb60220f8f --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import it.unibo.alchemist.boundary.dsl.AlchemistDsl +import it.unibo.alchemist.model.Action +import it.unibo.alchemist.model.Actionable +import it.unibo.alchemist.model.Condition +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.Reaction +import it.unibo.alchemist.model.TimeDistribution +import org.apache.commons.math3.random.RandomGenerator + +/** + * Context interface for configuring a single program (reaction) for a node. + * + * This context is used within [ProgramsContext] blocks to define reactions with + * their time distributions, conditions, and actions. + * + * @param T The type of molecule concentration. + * @param P The type of position, must extend [it.unibo.alchemist.model.Position]. + * + * @see [ProgramsContext] for the parent context + * @see [it.unibo.alchemist.model.Reaction] for the reaction interface + * @see [it.unibo.alchemist.model.TimeDistribution] for time distribution + * @see [it.unibo.alchemist.model.Action] for reaction actions + * @see [it.unibo.alchemist.model.Condition] for reaction conditions + */ +// TODO: remove when detekt false positive is fixed +@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters +@AlchemistDsl +interface ProgramContext> { + /** + * The programs context this program context belongs to. + */ + val ctx: ProgramsContext + + /** + * The node this program context is configuring. + */ + val node: Node + + /** + * The program specification as a string. + * + * The format depends on the incarnation being used. + */ + var program: String? + + /** + * The time distribution for the reaction. + * + * @see [it.unibo.alchemist.model.TimeDistribution] + */ + var timeDistribution: TimeDistribution? + + /** + * An optional custom reaction instance. + * + * If provided, this reaction will be used instead of creating one from [program]. + * + * @see [it.unibo.alchemist.model.Reaction] + */ + var reaction: Reaction? + + /** + * Sets the time distribution using a string specification. + * + * The string is processed by the incarnation to create a [TimeDistribution]. + * + * ```kotlin + * timeDistribution("1") + * ``` + * + * @param td The time distribution specification string. + * @see [TimeDistribution] + * @see [it.unibo.alchemist.model.Incarnation.createTimeDistribution] + */ + fun timeDistribution(td: String) + + /** + * Adds an action to the program. + * + * Actions are executed when the reaction fires and all conditions are met. + * + * @param block A factory function that creates the action. + * @see [it.unibo.alchemist.model.Action] + */ + fun addAction(block: () -> Action) + + /** + * Adds an action to the program using the incarnation createAction function. + * + * @param action the action + * @see [it.unibo.alchemist.model.Incarnation.createAction] + */ + context(_: Incarnation, _: RandomGenerator, _: Environment, _: Node, _: Actionable) + fun addAction(action: String) = addAction { + contextOf>().createAction( + contextOf(), + contextOf>(), + contextOf>(), + contextOf>(), + action, + ) + } + + /** + * Adds a condition to the program. + * + * Conditions must all be satisfied for the reaction to fire. + * + * @param block A factory function that creates the condition. + * @see [it.unibo.alchemist.model.Condition] + */ + fun addCondition(block: () -> Condition) + + /** + * Adds a condition to the program, using the incarnation createCondition function. + * + * @param condition the condition + * @see [Incarnation.createCondition] + */ + context(_: Incarnation, _: RandomGenerator, _: Environment, _: Node, _: Actionable) + fun addCondition(condition: String) = addCondition { + contextOf>().createCondition( + contextOf(), + contextOf>(), + contextOf>(), + contextOf>(), + condition, + ) + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt index 4bab9e942b..daadf520e5 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt @@ -10,8 +10,6 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.dsl.AlchemistDsl -import it.unibo.alchemist.model.Action -import it.unibo.alchemist.model.Condition import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position @@ -81,116 +79,3 @@ interface ProgramsContext> { block: context(Environment, Node) ProgramContext.() -> Unit, ) } - -/** - * Context interface for configuring a single program (reaction) for a node. - * - * This context is used within [ProgramsContext] blocks to define reactions with - * their time distributions, conditions, and actions. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - * - * @see [ProgramsContext] for the parent context - * @see [Reaction] for the reaction interface - * @see [TimeDistribution] for time distribution - * @see [Action] for reaction actions - * @see [Condition] for reaction conditions - */ -@AlchemistDsl -interface ProgramContext> { - /** - * The programs context this program context belongs to. - */ - val ctx: ProgramsContext - - /** - * The node this program context is configuring. - */ - val node: Node - - /** - * The program specification as a string. - * - * The format depends on the incarnation being used. - */ - var program: String? - - /** - * The time distribution for the reaction. - * - * @see [TimeDistribution] - */ - var timeDistribution: TimeDistribution? - - /** - * An optional custom reaction instance. - * - * If provided, this reaction will be used instead of creating one from [program]. - * - * @see [Reaction] - */ - var reaction: Reaction? - - /** - * Sets the time distribution using a string specification. - * - * The string is processed by the incarnation to create a [TimeDistribution]. - * - * ```kotlin - * timeDistribution("1") - * ``` - * - * @param td The time distribution specification string. - * @see [TimeDistribution] - * @see [it.unibo.alchemist.model.Incarnation.createTimeDistribution] - */ - fun timeDistribution(td: String) - - /** - * Adds an action to the program. - * - * Actions are executed when the reaction fires and all conditions are met. - * - * @param block A factory function that creates the action. - * @see [Action] - */ - fun addAction(block: () -> Action) - - /** - * Adds an action to the program using the incarnation createAction function. - * - * @param action the action - * @see [it.unibo.alchemist.model.Incarnation.createAction] - */ - fun addAction(action: String) - - /** - * Adds a condition to the program. - * - * Conditions must all be satisfied for the reaction to fire. - * - * @param block A factory function that creates the condition. - * @see [Condition] - */ - fun addCondition(block: () -> Condition) - - /** - * Adds a condition to the program, using the incarnation createCondition function. - * - * @param condition the condition - * @see [it.unibo.alchemist.model.Incarnation.createCondition] - */ - fun addCondition(condition: String) - - /** - * Unary plus operator for type-safe casting of [TimeDistribution]. - * - * This operator allows casting a [TimeDistribution] with wildcard type parameter - * to a specific type parameter, enabling type-safe usage in generic contexts. - * - * @return The same [TimeDistribution] instance cast to the specified type parameter. - */ - @Suppress("UNCHECKED_CAST") - operator fun TimeDistribution<*>.unaryPlus(): TimeDistribution = this as TimeDistribution -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt index 06cb0c1a30..5e2f68c6a5 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt @@ -157,35 +157,8 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex actions += block } - override fun addAction(action: String) { - actions += { - context.incarnation - .createAction( - context.simulationGenerator, - context.environment, - node, - timeDistribution, - reaction, - action, - ) - } - } - override fun addCondition(block: () -> Condition) { conditions += block } - - override fun addCondition(condition: String) { - conditions += { - context.incarnation.createCondition( - context.simulationGenerator, - context.environment, - node, - timeDistribution, - reaction, - condition, - ) - } - } } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SeedsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SeedsContext.kt new file mode 100644 index 0000000000..14031454c7 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SeedsContext.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import org.apache.commons.math3.random.RandomGenerator + +/** + * Context for defining random seeds for simulation and scenario generation. + */ +interface SeedsContext { + + /** + * Sets the scenario's random generator to the default with the specified seed. + * + * @param seed the seed value + */ + fun scenario(seed: Long) + + /** + * Sets the scenario's random generator using the provided block. + * + * @param block a lambda that returns a RandomGenerator + */ + fun scenario(block: () -> RandomGenerator) + + /** + * Sets the simulation's random generator to the default with the specified seed. + * + * @param seed the seed value + */ + fun simulation(seed: Long) + + /** + * Sets the simulation's random generator using the provided block. + * + * @param block a lambda that returns a RandomGenerator + */ + fun simulation(block: () -> RandomGenerator) +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index efc42760ea..1821a21e90 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -202,6 +202,8 @@ interface SimulationContext> { */ fun variable(source: () -> A): VariablesContext.DependentVariableProvider + fun seeds(block: SeedsContext.() -> Unit) + /** * The context managing variables for batch simulations. * diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt index 8d4ec69375..1117385d4d 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -34,6 +34,10 @@ class SimulationContextImpl>( override val incarnation: Incarnation, private val environmentFactory: context(Incarnation) () -> Environment, ) : SimulationContext { + + private var randomGeneratorForSimulation: () -> RandomGenerator = ::defaultRandomGenerator + private var randomGeneratorForScenario: () -> RandomGenerator = ::defaultRandomGenerator + /** The environment instance (internal use). */ override val environment: Environment by lazy { context(incarnation) { @@ -160,9 +164,30 @@ class SimulationContextImpl>( } } + override fun seeds(block: SeedsContext.() -> Unit) { + val seedContext = object : SeedsContext { + override fun simulation(seed: Long) = simulation { defaultRandomGenerator(seed) } + + override fun scenario(seed: Long) = scenario { defaultRandomGenerator(seed) } + + override fun simulation(block: () -> RandomGenerator) { + randomGeneratorForSimulation = block + } + + override fun scenario(block: () -> RandomGenerator) { + randomGeneratorForScenario = block + } + } + seedContext.block() + } + override fun variable(source: Variable): VariablesContext.VariableProvider = variablesContext.register(source) override fun variable(source: () -> A): VariablesContext.DependentVariableProvider = variablesContext.dependent(source) + + private companion object { + fun defaultRandomGenerator(seed: Long = 0L): RandomGenerator = MersenneTwister(seed) + } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt index f9471f6ab6..dcd90fe8f7 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt @@ -69,7 +69,7 @@ import org.apache.commons.math3.random.RandomGenerator */ private typealias Seeds = Pair private typealias ReactionComponentFunction = - (RandomGenerator, Environment, Node?, TimeDistribution, Actionable, Any?) -> R + (RandomGenerator, Environment, Node?, Actionable, Any?) -> R /* * UTILITY FUNCTIONS @@ -707,7 +707,7 @@ internal object SimulationModel { genericFactory: (Context, Any?) -> Result?, ): Result? { fun create(parameter: Any?, makeWith: ReactionComponentFunction): Result = runCatching { - makeWith(simulationRNG, environment, node, timeDistribution, actionable, parameter) + makeWith(simulationRNG, environment, node, actionable, parameter) } return when (parameter) { is String -> create(parameter, incarnationFactory) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index f828fba517..607e29d609 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -178,7 +178,7 @@ object DslLoaderFunctions { deploy(point(1.5, 0.5)) { programs { all { - timeDistribution = +JaktaTimeDistribution( + timeDistribution = JaktaTimeDistribution( sense = weibullTime( 1.0, 1.0, diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt index 4b9d051771..735b4c71c0 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt @@ -69,8 +69,6 @@ object RuntimeComparisonHelper { steps: Long? = null, targetTime: Double? = null, stableForSteps: Pair? = null, - timeTolerance: Double = 0.01, - positionTolerance: Double? = null, ) { val terminationMethods = listOfNotNull( steps?.let { "steps" }, @@ -102,8 +100,6 @@ object RuntimeComparisonHelper { targetTime, stableForSteps, steps, - timeTolerance, - positionTolerance, ) } catch (e: Exception) { fail("Error during simulation execution: ${e.message}") @@ -162,8 +158,6 @@ object RuntimeComparisonHelper { targetTime: Double?, stableForSteps: Pair?, steps: Long?, - timeTolerance: Double, - positionTolerance: Double?, ) { println("Running DSL simulation...") runSimulationSynchronously(dslSimulation) @@ -178,13 +172,10 @@ object RuntimeComparisonHelper { "step: ${yamlSimulation.step}, time: ${yamlSimulation.time}", ) checkSimulationTimeAdvancement(dslSimulation, yamlSimulation, effectiveSteps, targetTime, stableForSteps) - val effectivePositionTolerance = positionTolerance ?: max(timeTolerance * 10, 1e-6) compareRuntimeStates( dslSimulation, yamlSimulation, - timeTolerance, compareSteps = steps != null, - positionTolerance = effectivePositionTolerance, ) } @@ -283,9 +274,7 @@ object RuntimeComparisonHelper { private fun > compareRuntimeStates( dslSimulation: Simulation, yamlSimulation: Simulation, - timeTolerance: Double = 0.01, compareSteps: Boolean = true, - positionTolerance: Double = 1e-6, ) { println("Comparing runtime simulation states...") @@ -293,10 +282,10 @@ object RuntimeComparisonHelper { val yamlEnv = yamlSimulation.environment // Compare simulation execution state - compareSimulationExecutionState(dslSimulation, yamlSimulation, timeTolerance, compareSteps) + compareSimulationExecutionState(dslSimulation, yamlSimulation, compareSteps) // Compare environment states - compareRuntimeEnvironmentStates(dslEnv, yamlEnv, positionTolerance) + compareRuntimeEnvironmentStates(dslEnv, yamlEnv) } /** @@ -305,23 +294,16 @@ object RuntimeComparisonHelper { private fun > compareSimulationExecutionState( dslSimulation: Simulation, yamlSimulation: Simulation, - timeTolerance: Double = 0.01, compareSteps: Boolean = true, ) { println("Comparing simulation execution state...") - val dslTime = dslSimulation.time.toDouble() val yamlTime = yamlSimulation.time.toDouble() - val timeDiff = abs(dslTime - yamlTime) - println("DSL simulation time: ${dslSimulation.time}, step: ${dslSimulation.step}") println("YAML simulation time: ${yamlSimulation.time}, step: ${yamlSimulation.step}") - println("Time difference: ${timeDiff}s (tolerance: ${timeTolerance}s)") - - if (timeDiff > timeTolerance) { + if (dslTime != yamlTime) { fail( - "Simulation times differ by ${timeDiff}s (tolerance: ${timeTolerance}s). " + - "DSL: ${dslTime}s, YAML: ${yamlTime}s", + "Simulation times differ by ${abs(dslTime - yamlTime)}s. DSL: ${dslTime}s, YAML: ${yamlTime}s", ) } @@ -370,7 +352,6 @@ object RuntimeComparisonHelper { private fun > compareRuntimeEnvironmentStates( dslEnv: Environment, yamlEnv: Environment, - positionTolerance: Double = 1e-6, ) { println("Comparing runtime environment states...") @@ -388,7 +369,7 @@ object RuntimeComparisonHelper { ) // Compare node positions and contents - compareRuntimeNodeStates(dslEnv, yamlEnv, positionTolerance) + compareRuntimeNodeStates(dslEnv, yamlEnv) // Compare global reactions compareRuntimeGlobalReactions(dslEnv, yamlEnv) @@ -402,28 +383,22 @@ object RuntimeComparisonHelper { * * @param positionTolerance Maximum distance between positions to consider them matching (default: 1e-6) */ - private fun > compareRuntimeNodeStates( - dslEnv: Environment, - yamlEnv: Environment, - positionTolerance: Double = 1e-6, - ) { - println("Comparing runtime node states... (position tolerance: $positionTolerance)") + private fun > compareRuntimeNodeStates(dslEnv: Environment, yamlEnv: Environment) { + println("Comparing runtime node states...") val dslNodesWithPos = dslEnv.nodes.map { it to dslEnv.getPosition(it) } val yamlNodesWithPos = yamlEnv.nodes.map { it to yamlEnv.getPosition(it) }.toMutableList() val (matchedPairs, unmatchedDslNodes, distances) = matchNodesByPosition( dslNodesWithPos, yamlNodesWithPos, - positionTolerance, ) printMatchingStatistics(distances, matchedPairs, dslNodesWithPos.size) - checkUnmatchedNodes(unmatchedDslNodes, yamlNodesWithPos, distances, positionTolerance) - compareMatchedNodes(matchedPairs, dslEnv, yamlEnv, positionTolerance) + checkUnmatchedNodes(unmatchedDslNodes, yamlNodesWithPos, distances) + compareMatchedNodes(matchedPairs, dslEnv, yamlEnv) } private fun > matchNodesByPosition( dslNodesWithPos: List, P>>, yamlNodesWithPos: MutableList, P>>, - positionTolerance: Double, ): Triple, Node>>, List, P>>, List> { val matchedPairs = mutableListOf, Node>>() val unmatchedDslNodes = mutableListOf, P>>() @@ -437,7 +412,7 @@ object RuntimeComparisonHelper { val (yamlNode, yamlPos) = closest val distance = dslPos.distanceTo(yamlPos) distances.add(distance) - if (distance <= positionTolerance) { + if (distance != 0.0) { matchedPairs.add(dslNode to yamlNode) yamlNodesWithPos.remove(closest) } else { @@ -471,7 +446,6 @@ object RuntimeComparisonHelper { unmatchedDslNodes: List, P>>, yamlNodesWithPos: List, P>>, distances: List, - positionTolerance: Double, ) { if (unmatchedDslNodes.isNotEmpty()) { val minDistance = distances.minOrNull() ?: Double.MAX_VALUE @@ -485,7 +459,7 @@ object RuntimeComparisonHelper { } fail( "DSL simulation has ${unmatchedDslNodes.size} unmatched nodes " + - "(tolerance: $positionTolerance). Distance stats: min=$minDistance, " + + "Distance stats: min=$minDistance, " + "max=$maxDistance, avg=$avgDistance. First 10 positions: $positions$moreInfo", ) } @@ -507,17 +481,13 @@ object RuntimeComparisonHelper { matchedPairs: List, Node>>, dslEnv: Environment, yamlEnv: Environment, - positionTolerance: Double, ) { for ((dslNode, yamlNode) in matchedPairs) { val dslPos = dslEnv.getPosition(dslNode) val yamlPos = yamlEnv.getPosition(yamlNode) val distance = dslPos.distanceTo(yamlPos) - if (distance > positionTolerance) { - println( - "WARNING: Matched nodes have distance $distance " + - "(tolerance: $positionTolerance)", - ) + if (distance != 0.0) { + println("WARNING: Matched nodes have distance $distance ") } compareNodeContentsAtPosition(dslNode, yamlNode, dslPos) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt index 5fa9be9261..537fcc0791 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt @@ -31,7 +31,6 @@ object TestComparators { * Exactly one of steps, targetTime, or stableForSteps must be provided. * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). * Exactly one of steps, targetTime, or stableForSteps must be provided. - * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s). */ fun > compare( dslLoader: () -> Loader, @@ -40,7 +39,6 @@ object TestComparators { steps: Long? = null, targetTime: Double? = null, stableForSteps: Pair? = null, - timeTolerance: Double = 0.01, ) { val yamlLoader = LoaderFactory.loadYaml(yamlResource) // Always perform static comparison @@ -54,8 +52,6 @@ object TestComparators { steps = steps, targetTime = targetTime, stableForSteps = stableForSteps, - timeTolerance = timeTolerance, - positionTolerance = null, ) } } @@ -72,7 +68,6 @@ object TestComparators { * Exactly one of steps, targetTime, or stableForSteps must be provided. * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). * Exactly one of steps, targetTime, or stableForSteps must be provided. - * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s). */ fun > compare( dslCode: String, @@ -81,11 +76,10 @@ object TestComparators { steps: Long? = null, targetTime: Double? = null, stableForSteps: Pair? = null, - timeTolerance: Double = 0.01, ) { compare({ LoaderFactory.loadDsl(dslCode) - }, yamlResource, includeRuntime, steps, targetTime, stableForSteps, timeTolerance) + }, yamlResource, includeRuntime, steps, targetTime, stableForSteps) } /** @@ -100,7 +94,6 @@ object TestComparators { * Exactly one of steps, targetTime, or stableForSteps must be provided. * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). * Exactly one of steps, targetTime, or stableForSteps must be provided. - * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s). */ fun > compare( dslLoader: Loader, @@ -109,7 +102,6 @@ object TestComparators { steps: Long? = null, targetTime: Double? = null, stableForSteps: Pair? = null, - timeTolerance: Double = 0.01, ) { // Always perform static comparison StaticComparisonHelper.compareBasicProperties(dslLoader, yamlLoader) @@ -122,8 +114,6 @@ object TestComparators { steps = steps, targetTime = targetTime, stableForSteps = stableForSteps, - timeTolerance = timeTolerance, - positionTolerance = null, ) } } @@ -160,7 +150,6 @@ fun Loader.shouldEqual(yamlResource: String) { * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. - * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s) */ fun Loader.shouldEqual( other: Loader, @@ -168,9 +157,7 @@ fun Loader.shouldEqual( steps: Long? = null, targetTime: Double? = null, stableForSteps: Pair? = null, - timeTolerance: Double = 0.01, ) { - @Suppress("UNCHECKED_CAST") TestComparators.compare( this, other, @@ -178,7 +165,6 @@ fun Loader.shouldEqual( computeEffectiveSteps(includeRuntime, steps, targetTime, stableForSteps), targetTime, stableForSteps, - timeTolerance, ) } @@ -193,8 +179,6 @@ fun Loader.shouldEqual( * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. - * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s) - * * @note For simulations to advance time, all reactions must have explicit time distributions. * Reactions without time distributions default to "Infinity" rate, which schedules * them at time 0.0, preventing time from advancing. @@ -212,9 +196,7 @@ fun (() -> Loader).shouldEqual( steps: Long? = null, targetTime: Double? = null, stableForSteps: Pair? = null, - timeTolerance: Double = 0.01, ) { - @Suppress("UNCHECKED_CAST") TestComparators.compare( this, yamlResource, @@ -222,6 +204,5 @@ fun (() -> Loader).shouldEqual( computeEffectiveSteps(includeRuntime, steps, targetTime, stableForSteps), targetTime, stableForSteps, - timeTolerance, ) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/jakta/timedistributions/JaktaTimeDistribution.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/jakta/timedistributions/JaktaTimeDistribution.kt index e3d1ab2c22..d496cf4aff 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/jakta/timedistributions/JaktaTimeDistribution.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/jakta/timedistributions/JaktaTimeDistribution.kt @@ -14,19 +14,19 @@ import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Time import it.unibo.alchemist.model.TimeDistribution -data class JaktaTimeDistribution( - val sense: TimeDistribution, - val deliberate: TimeDistribution, - val act: TimeDistribution, -) : TimeDistribution { - override fun update(currentTime: Time, executed: Boolean, param: Double, environment: Environment) = +data class JaktaTimeDistribution( + val sense: TimeDistribution, + val deliberate: TimeDistribution, + val act: TimeDistribution, +) : TimeDistribution { + override fun update(currentTime: Time, executed: Boolean, param: Double, environment: Environment) = doNotUse() override fun getNextOccurence(): Time = doNotUse() override fun getRate(): Double = doNotUse() - override fun cloneOnNewNode(destination: Node, currentTime: Time): TimeDistribution = doNotUse() + override fun cloneOnNewNode(destination: Node, currentTime: Time): TimeDistribution = doNotUse() private fun doNotUse(): Nothing = error( "${this::class.simpleName} is not meant to be used directly, but to host custom time distributions" + diff --git a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts index 9f158abbf9..4e650dc05f 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts @@ -14,9 +14,7 @@ import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.boundary.extractors.Time import org.apache.commons.math3.random.MersenneTwister -val incarnation = SAPERE.incarnation() -val environment = {Continuous2DEnvironment(incarnation)} -simulation(incarnation, environment) { +simulation(SAPEREIncarnation()) { simulationGenerator = MersenneTwister(24L) scenarioGenerator = MersenneTwister(42L) From cc0ac84e9a6676b6a2b0f0dd583a46684d075fbb Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Tue, 27 Jan 2026 19:23:44 +0100 Subject: [PATCH 152/196] refactor: update random generator initialization and improve time distribution context --- .../alchemist/boundary/dsl/model/ProgramContext.kt | 1 + .../boundary/dsl/model/ProgramsContextImpl.kt | 11 +++++++---- .../it/unibo/alchemist/dsl/DslLoaderFunctions.kt | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt index eb60220f8f..314bd25cb9 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt @@ -86,6 +86,7 @@ interface ProgramContext> { * @see [TimeDistribution] * @see [it.unibo.alchemist.model.Incarnation.createTimeDistribution] */ + context(_: Incarnation, _: RandomGenerator, _: Environment, _: Node) fun timeDistribution(td: String) /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt index 5e2f68c6a5..5104a985ed 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt @@ -14,11 +14,13 @@ import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Condition import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter import it.unibo.alchemist.model.Reaction import it.unibo.alchemist.model.TimeDistribution +import org.apache.commons.math3.random.RandomGenerator /** * Context for managing programs (reactions) in a simulation. @@ -144,11 +146,12 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex */ override var reaction: Reaction? = null + context(_: Incarnation, _: RandomGenerator, _: Environment, _: Node) override fun timeDistribution(td: String) { - timeDistribution = context.incarnation.createTimeDistribution( - context.simulationGenerator, - context.environment, - node, + timeDistribution = contextOf>().createTimeDistribution( + contextOf(), + contextOf>(), + contextOf>(), td, ) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 607e29d609..2e7993b53b 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -72,8 +72,10 @@ object DslLoaderFunctions { fun test02ManyNodes(): Loader { val incarnation = SAPEREIncarnation() return simulation(incarnation) { - simulationGenerator = MersenneTwister(10L) - scenarioGenerator = MersenneTwister(20L) + seeds { + simulation(10L) + scenario(20L) + } networkModel = ConnectWithinDistance(0.5) deployments { deploy( From 57c54e432f96a2e193bd9512be8d4de88e1ef317 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 29 Jan 2026 19:40:59 +0100 Subject: [PATCH 153/196] DSL2 --- .../dsl/processor/DslBuilderProcessor.kt | 3 +- .../unibo/alchemist/boundary/dsl/DSLLoader.kt | 5 +- .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 52 +-- .../boundary/dsl/model/DeploymentsContext.kt | 8 +- .../dsl/model/DeploymentsContextImpl.kt | 20 +- .../dsl/model/OutputMonitorsContext.kt | 10 +- .../boundary/dsl/model/ProgramsContextImpl.kt | 63 +-- .../dsl/model/RandomGeneratorProvider.kt | 20 + .../boundary/dsl/model/SimulationContext.kt | 18 +- .../dsl/model/SimulationContextImpl.kt | 53 ++- alchemist-loading/src/test/kotlin/DSL2.kt | 378 ++++++++++++++++++ .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 55 +-- .../it/unibo/alchemist/dsl/TestContents.kt | 3 +- .../it/unibo/alchemist/dsl/TestDeployments.kt | 7 +- 14 files changed, 544 insertions(+), 151 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/RandomGeneratorProvider.kt create mode 100644 alchemist-loading/src/test/kotlin/DSL2.kt diff --git a/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt index 44608d7a15..11974d0834 100644 --- a/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt +++ b/alchemist-factories-generator/src/jvmMain/kotlin/it/unibo/alchemist/boundary/dsl/processor/DslBuilderProcessor.kt @@ -31,6 +31,7 @@ import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Reaction +import it.unibo.alchemist.model.TimeDistribution import java.io.PrintWriter import java.nio.charset.StandardCharsets import org.apache.commons.math3.random.RandomGenerator @@ -74,11 +75,11 @@ class DslBuilderProcessor(private val codeGenerator: CodeGenerator) : SymbolProc fun injectableTypes(): Set = sequenceOf( resolver.getClassDeclarationByName>(), resolver.getClassDeclarationByName>(), - resolver.getClassDeclarationByName>(), resolver.getClassDeclarationByName>(), resolver.getClassDeclarationByName(), resolver.getClassDeclarationByName>(), resolver.getClassDeclarationByName>(), + resolver.getClassDeclarationByName>(), ).map { checkNotNull(it).asStarProjectedType() }.toSet() private fun processConstructor( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt index 4746135e03..4c5c2395a5 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt @@ -26,8 +26,6 @@ import java.util.concurrent.Semaphore */ abstract class DSLLoader(private val ctx: SimulationContext<*, *>) : Loader { - protected abstract fun > envFactory(): Environment - @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation = SingleUseLoader(ctx as SimulationContext).load(values) @@ -45,7 +43,6 @@ abstract class DSLLoader(private val ctx: SimulationContext<*, *>) : Loader { mutex.release() } val typedCtx = ctx as SimulationContextImpl - val envInstance = envFactory() val unknownVariableNames = values.keys - this@DSLLoader.variables.keys require(unknownVariableNames.isEmpty()) { "Unknown variables provided: $unknownVariableNames." + @@ -57,7 +54,7 @@ abstract class DSLLoader(private val ctx: SimulationContext<*, *>) : Loader { k to v() }.toMap(), ) - val simulationIstance = typedCtx.build(envInstance, values) + val simulationIstance = typedCtx.build(values) val environment = simulationIstance.environment val engine = Engine(environment) // MONITORS diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt index b9dd80963d..3eb82ced93 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt @@ -19,6 +19,7 @@ import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.environments.Euclidean2DEnvironment import it.unibo.alchemist.model.positions.Euclidean2DPosition import org.apache.commons.math3.random.RandomGenerator @@ -44,63 +45,46 @@ object Dsl { * @param dsl The simulation context. * @return A loader instance. */ - fun > createLoader( - builder: SimulationContext, - envBuilder: () -> Environment, - ): Loader = object : DSLLoader(builder) { - override val constants: Map = emptyMap() - override val dependentVariables: Map> = emptyMap() - override val variables: Map> = builder.variablesContext.variables - override val remoteDependencies: List = emptyList() - override val launcher: Launcher = builder.launcher - - @Suppress("UNCHECKED_CAST") - override fun > envFactory(): Environment = envBuilder() as Environment - } + private fun , E : Environment> createLoader(builder: SimulationContext): Loader = + object : DSLLoader(builder) { + override val constants: Map = emptyMap() + override val dependentVariables: Map> = emptyMap() + override val variables: Map> = builder.variablesContext.variables + override val remoteDependencies: List = emptyList() + override val launcher: Launcher = builder.launcher + } /** * Creates a simulation with a custom environment. * * @param incarnation The incarnation instance. - * @param environmentFactory The environment instance. * @param block The simulation configuration block. * @return A loader instance. */ - fun > simulation( + fun , E : Environment> simulation( incarnation: Incarnation, - environmentFactory: context(Incarnation) () -> Environment, block: context( Incarnation, RandomGenerator, - Environment, - ) SimulationContext.() -> Unit, + ) SimulationContext.() -> Unit, ): Loader { - val ctx = SimulationContextImpl(incarnation, environmentFactory) + val ctx = SimulationContextImpl(incarnation) ctx.apply { - context(incarnation, ctx.scenarioGenerator, ctx.environment) { + context(incarnation, ctx.scenarioGenerator) { block() } } - return createLoader(ctx) { - context(incarnation) { - environmentFactory() - } - } + return createLoader(ctx) } /** - * Creates a simulation with a default 2D continuous environment. - * - * @param incarnation The incarnation instance. - * @param block The simulation configuration block. - * @return A loader instance. + * Creates a 2D simulation with a Euclidean2DEnvironment. */ - fun simulation( + fun simulation2D( incarnation: Incarnation, block: context( Incarnation, RandomGenerator, - Environment, - ) SimulationContext.() -> Unit, - ): Loader = simulation(incarnation, { Continuous2DEnvironment(incarnation) }, block) + ) SimulationContext>.() -> Unit, + ): Loader = simulation>(incarnation, block) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt index 8e29369669..41003e3d71 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt @@ -11,6 +11,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import org.apache.commons.math3.random.RandomGenerator @@ -50,11 +51,6 @@ import org.apache.commons.math3.random.RandomGenerator */ @Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters interface DeploymentsContext> { - /** - * The simulation context this deployments context belongs to. - */ - val ctx: SimulationContext - /** * Deploys nodes using a deployment with a configuration block. * @@ -71,7 +67,7 @@ interface DeploymentsContext> { * @see [it.unibo.alchemist.model.Deployment] */ // TODO: fix the doc - context(environment: Environment) + context(_: Incarnation, environment: Environment) fun deploy( deployment: Deployment

, nodeFactory: context(RandomGenerator, Environment) () -> Node = { diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt index 7c3baf269e..26029c15cc 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt @@ -13,6 +13,7 @@ import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter @@ -27,26 +28,26 @@ import org.apache.commons.math3.random.RandomGenerator * @param P The type of position. * @param ctx The simulation context. */ -open class DeploymentsContextImpl>(override val ctx: SimulationContext) : +open class DeploymentsContextImpl>(private val simulationRandomGenerator: RandomGenerator) : DeploymentsContext { - context(environment: Environment) + context(_: Incarnation, environment: Environment) override fun deploy( deployment: Deployment

, nodeFactory: context(RandomGenerator, Environment) () -> Node, block: context(Environment, Node) DeploymentContext.() -> Unit, ) { - context(ctx.simulationGenerator) { + context(simulationRandomGenerator) { logger.debug("Deploying deployment: {}", deployment) // Additional linking rules deployment.getAssociatedLinkingRule()?.let { newLinkingRule -> val composedLinkingRule = - when (val linkingRule = ctx.environment.linkingRule) { + when (val linkingRule = environment.linkingRule) { is NoLinks -> newLinkingRule is CombinedLinkingRule -> CombinedLinkingRule(linkingRule.subRules + listOf(newLinkingRule)) else -> CombinedLinkingRule(listOf(linkingRule, newLinkingRule)) } - ctx.environment.linkingRule = composedLinkingRule + environment.linkingRule = composedLinkingRule } deployment.forEach { position -> logger.debug("visiting position: {} for deployment: {}", position, deployment) @@ -76,7 +77,7 @@ open class DeploymentsContextImpl>(override val ctx: Simulati logger.debug("programs={}", createdPrograms) logger.debug("Adding node to environment at position: {}", position) } - ctx.environment.addNode(node, position) + environment.addNode(node, position) } } } @@ -138,16 +139,17 @@ open class DeploymentsContextImpl>(override val ctx: Simulati * @param position The position of the node. * @param content The content context to apply. */ - fun applyToNodes(node: Node, position: P, content: ContentContextImpl) { + context(incarnation: Incarnation) + internal fun applyToNodes(node: Node, position: P, content: ContentContextImpl) { logger.debug("Applying node to nodes for position: {}, deployment {}", position, deployment) if (content.filter == null || content.filter.contains(position)) { logger.debug("Creating molecule for node at position: {}", position) - val mol = ctx.ctx.incarnation.createMolecule( + val mol = incarnation.createMolecule( content.molecule ?: error("Molecule not specified"), ) logger.debug("Creating concentration for molecule: {}", mol) - val conc = ctx.ctx.incarnation.createConcentration(content.concentration) + val conc = incarnation.createConcentration(content.concentration) logger.debug("Setting concentration for molecule: {} to node at position: {}", mol, position) node.setConcentration(mol, conc) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt index 4d607c4aeb..9e485d62f3 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt @@ -10,6 +10,7 @@ package it.unibo.alchemist.boundary.dsl.model import it.unibo.alchemist.boundary.OutputMonitor +import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position /** @@ -18,9 +19,9 @@ import it.unibo.alchemist.model.Position * @param T The type of molecule concentration. * @param P The type of position. */ -interface OutputMonitorsContext> { +interface OutputMonitorsContext, E : Environment> { /** The parent simulation context. */ - val ctx: SimulationContext + val ctx: SimulationContext /** * Adds an output monitor to the simulation. @@ -36,8 +37,9 @@ interface OutputMonitorsContext> { * @param T The type of molecule concentration. * @param P The type of position. */ -class OutputMonitorsContextImpl>(override val ctx: SimulationContextImpl) : - OutputMonitorsContext { +class OutputMonitorsContextImpl, E : Environment>( + override val ctx: SimulationContextImpl, +) : OutputMonitorsContext { override fun OutputMonitor.unaryPlus() { ctx.monitors += this } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt index 5104a985ed..889dad7eea 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt @@ -70,44 +70,46 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex * @param program The program configuration block. * @param filter Optional position filter. */ + context(incarnation: Incarnation, simulationRandomGenerator: RandomGenerator, environment: Environment) fun applyToNodes( node: Node, position: P, program: context(Environment, Node) ProgramContextImpl.() -> Unit, filter: PositionBasedFilter

?, ): Pair?, Actionable> { - context(ctx.ctx.ctx.environment, node) { - logger.debug("Applying program to node at position: {}", position) - val c = ProgramContextImpl(node).apply { program() } - val context = ctx.ctx.ctx - logger.debug("Creating time distribution for program") - val timeDistribution = c.timeDistribution - ?: context.incarnation.createTimeDistribution( - context.simulationGenerator, - context.environment, - node, - null, - ) - logger.debug("Creating reaction for program") - val r = c.reaction - ?: // Create a basic reaction with custom actions/conditions - context.incarnation.createReaction( - context.simulationGenerator, - context.environment, - node, - timeDistribution, - c.program, - ) - logger.debug("Adding actions to reaction") - r.actions += c.actions.map { it() } - logger.debug("Adding conditions to reaction") - r.conditions += c.conditions.map { it() } - logger.debug("Adding reaction to node") - if (filter == null || filter.contains(position)) { - node.addReaction(r) + logger.debug("Applying program to node at position: {}", position) + val c = ProgramContextImpl(node).apply { + context(node) { + program() } - return filter to r } + logger.debug("Creating time distribution for program") + val timeDistribution = c.timeDistribution + ?: incarnation.createTimeDistribution( + simulationRandomGenerator, + environment, + node, + null, + ) + logger.debug("Creating reaction for program") + val r = c.reaction + ?: // Create a basic reaction with custom actions/conditions + incarnation.createReaction( + simulationRandomGenerator, + environment, + node, + timeDistribution, + c.program, + ) + logger.debug("Adding actions to reaction") + r.actions += c.actions.map { it() } + logger.debug("Adding conditions to reaction") + r.conditions += c.conditions.map { it() } + logger.debug("Adding reaction to node") + if (filter == null || filter.contains(position)) { + node.addReaction(r) + } + return filter to r } /** @@ -119,7 +121,6 @@ class ProgramsContextImpl>(override val ctx: DeploymentContex open inner class ProgramContextImpl(override val node: Node) : ProgramContext { override val ctx: ProgramsContext = this@ProgramsContextImpl - private val context = ctx.ctx.ctx.ctx /** * The program name. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/RandomGeneratorProvider.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/RandomGeneratorProvider.kt new file mode 100644 index 0000000000..1889fd7368 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/RandomGeneratorProvider.kt @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.dsl.model + +import java.util.random.RandomGenerator + +/** + * Provides random generators for different simulation contexts. + * + * @param forScenario The random generator for the scenario context. + * @param forSimulation The random generator for the simulation context. + */ +data class RandomGeneratorProvider(val forScenario: RandomGenerator, val forSimulation: RandomGenerator) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt index 1821a21e90..47d2766ec6 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt @@ -54,7 +54,7 @@ import org.apache.commons.math3.random.RandomGenerator * @see [LayerContextImpl] for layer configuration */ @Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -interface SimulationContext> { +interface SimulationContext, E : Environment> { /** * The incarnation instance that defines how molecules, nodes, and reactions are created. * @@ -67,7 +67,7 @@ interface SimulationContext> { * * @see [Environment] */ - val environment: Environment + val environment: E /** * The launcher responsible for executing the simulation. @@ -99,6 +99,9 @@ interface SimulationContext> { */ var networkModel: LinkingRule + context(_: Incarnation) + fun environment(block: context(Incarnation) () -> E) + /** * Configures node deployments for the simulation. * @@ -112,8 +115,8 @@ interface SimulationContext> { * * @see [DeploymentsContextImpl] to configure deployments */ - context(randomGenerator: RandomGenerator, environment: Environment) - fun deployments(block: DeploymentsContext.() -> Unit) + context(_: Incarnation) + fun deployments(block: context(Incarnation, RandomGenerator, E) DeploymentsContext.() -> Unit) /** * Adds a termination predicate to the simulation. @@ -126,7 +129,7 @@ interface SimulationContext> { /** * Adds an output monitor to the simulation. * - * @param monitor The output monitor to add + * @param block The output monitor to add * @see [OutputMonitor] */ fun monitors(block: OutputMonitorsContext.() -> Unit) @@ -142,7 +145,7 @@ interface SimulationContext> { /** * Configures a global program. * - * @param program the global reaction to add + * @param block the global reaction to add * @see [GlobalReaction] */ fun programs(block: GlobalProgramsContext.() -> Unit) @@ -163,7 +166,8 @@ interface SimulationContext> { * * @param block The block of code to execute later */ - fun runLater(block: context(SimulationContext) () -> Unit) + // TODO: should be removed + fun runLater(block: context(SimulationContext) () -> Unit) /** * Add a spatial layer for a molecule. diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt index 1117385d4d..b2cedaee8a 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt @@ -19,6 +19,8 @@ import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.positions.Euclidean2DPosition import java.io.Serializable import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator @@ -30,16 +32,19 @@ import org.apache.commons.math3.random.RandomGenerator * @param P The type of position. */ -class SimulationContextImpl>( +class SimulationContextImpl, E : Environment>( override val incarnation: Incarnation, - private val environmentFactory: context(Incarnation) () -> Environment, -) : SimulationContext { + private var environmentFactory: context(Incarnation) () -> E, +) : SimulationContext { private var randomGeneratorForSimulation: () -> RandomGenerator = ::defaultRandomGenerator private var randomGeneratorForScenario: () -> RandomGenerator = ::defaultRandomGenerator + private val simRNG by lazy { randomGeneratorForSimulation() } + private val scenarioRNG by lazy { randomGeneratorForScenario() } + /** The environment instance (internal use). */ - override val environment: Environment by lazy { + override val environment: E by lazy { context(incarnation) { environmentFactory() } @@ -48,7 +53,7 @@ class SimulationContextImpl>( /** * List of build steps to execute. */ - val buildSteps: MutableList.() -> Unit> = mutableListOf() + val buildSteps: MutableList.() -> Unit> = mutableListOf() /** * List of output . @@ -108,8 +113,8 @@ class SimulationContextImpl>( * its own variables spaces: check the [VariablesContext] documentation for more details. * @see [VariablesContext] */ - fun build(envInstance: Environment, values: Map): SimulationContextImpl { - val batchContext = SimulationContextImpl(incarnation) { envInstance } + fun build(values: Map): SimulationContextImpl { + val batchContext = SimulationContextImpl(incarnation) batchContext.variablesContext.variables += this.variablesContext.variables batchContext.variablesContext.dependentVariables += this.variablesContext.dependentVariables logger.debug("Binding variables to batchInstance: {}", values) @@ -118,33 +123,40 @@ class SimulationContextImpl>( return batchContext } - context(randomGenerator: RandomGenerator, environment: Environment) - override fun deployments(block: DeploymentsContext.() -> Unit) { - logger.debug("adding deployments block inside {}", this) + context(_: Incarnation) + override fun deployments( + block: context(Incarnation, RandomGenerator, E) DeploymentsContext.() -> Unit, + ) { buildSteps.add { logger.debug("Configuring deployments inside {}", this) - DeploymentsContextImpl(this).apply(block) + context(scenarioRNG) { + DeploymentsContextImpl(simRNG).apply { + context(environment) { + block() + } + } + } } } - override fun terminators(block: TerminatorsContext.() -> Unit) { - @Suppress("UNCHECKED_CAST") - buildSteps.add { TerminatorsContextImpl(this).block() } + context(_: Incarnation) + override fun environment(block: context(Incarnation) () -> E) { + environmentFactory = block } override fun monitors(block: OutputMonitorsContext.() -> Unit) { - buildSteps.add { OutputMonitorsContextImpl(this).block() } + buildSteps.add { OutputMonitorsContextImpl(this).block() } } override fun exporter(block: ExporterContext.() -> Unit) { - buildSteps.add { this._exporters.add(ExporterContextImpl(this).apply(block)) } + buildSteps.add { this._exporters.add(ExporterContextImpl(this).apply(block)) } } override fun programs(block: GlobalProgramsContext.() -> Unit) { - buildSteps.add { GlobalProgramsContextImpl(this).block() } + buildSteps.add { GlobalProgramsContextImpl(this).block() } } - override fun runLater(block: context(SimulationContext)() -> Unit) { + override fun runLater(block: context(SimulationContext)() -> Unit) { buildSteps.add { block() } } @@ -181,6 +193,11 @@ class SimulationContextImpl>( seedContext.block() } + override fun terminators(block: TerminatorsContext.() -> Unit) { + @Suppress("UNCHECKED_CAST") + buildSteps.add { TerminatorsContextImpl(this).block() } + } + override fun variable(source: Variable): VariablesContext.VariableProvider = variablesContext.register(source) diff --git a/alchemist-loading/src/test/kotlin/DSL2.kt b/alchemist-loading/src/test/kotlin/DSL2.kt new file mode 100644 index 0000000000..4d2ce41e07 --- /dev/null +++ b/alchemist-loading/src/test/kotlin/DSL2.kt @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package attempt + +import another.location.SimpleMonitor +import com.lowagie.tools.BuildTutorial.action +import it.unibo.alchemist.boundary.OutputMonitor +import it.unibo.alchemist.boundary.dsl.Dsl +import it.unibo.alchemist.dsl.DslLoaderFunctions +import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution +import it.unibo.alchemist.model.Action +import it.unibo.alchemist.model.Actionable +import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.GeoPosition +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.LinkingRule +import it.unibo.alchemist.model.Molecule +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.PositionBasedFilter +import it.unibo.alchemist.model.Reaction +import it.unibo.alchemist.model.TerminationPredicate +import it.unibo.alchemist.model.Time +import it.unibo.alchemist.model.TimeDistribution +import it.unibo.alchemist.model.deployments.circle +import it.unibo.alchemist.model.deployments.grid +import it.unibo.alchemist.model.deployments.point +import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.environments.continuous2DEnvironment +import it.unibo.alchemist.model.incarnations.ProtelisIncarnation +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation +import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance +import it.unibo.alchemist.model.maps.actions.reproduceGPSTrace +import it.unibo.alchemist.model.maps.deployments.FromGPSTrace +import it.unibo.alchemist.model.maps.environments.oSMEnvironment +import it.unibo.alchemist.model.positionfilters.Rectangle +import it.unibo.alchemist.model.positions.Euclidean2DPosition +import it.unibo.alchemist.model.reactions.event +import it.unibo.alchemist.model.sapere.ILsaMolecule +import it.unibo.alchemist.model.terminators.StableForSteps +import it.unibo.alchemist.model.timedistributions.DiracComb +import it.unibo.alchemist.model.timedistributions.exponentialTime +import it.unibo.alchemist.model.timedistributions.weibullTime +import org.apache.commons.math3.random.RandomGenerator + +interface ActionableContext { + fun action(action: Action) +} + +interface ContentContext { + + context(incarnation: Incarnation) + fun concentrationOf(origin: Any?) = incarnation.createConcentration(origin) + + operator fun Pair.unaryMinus() + + context(incarnation: Incarnation) + operator fun Molecule.unaryMinus() = -Pair(this, incarnation.createConcentration()) + + context(incarnation: Incarnation) + operator fun String.unaryMinus() = -Pair(incarnation.createMolecule(this), incarnation.createConcentration()) + + context(incarnation: Incarnation) + operator fun Pair.unaryMinus() = -Pair(incarnation.createMolecule(first), second) + +} + +interface DeploymentContext> { + + val position: P + + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) + fun program(timeDistribution: TimeDistribution, actionable: Actionable, block: context(Reaction) ActionableContext.() -> Unit = { }) + + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) + fun program( + timeDistribution: TimeDistribution, + actionable: context(TimeDistribution) () -> Actionable = { makeReaction(timeDistribution, null) }, + block: context(Reaction) ActionableContext.() -> Unit = { } + ) = program(timeDistribution, context(timeDistribution) { actionable() }, block) + + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) + fun program( + timeDistribution: Any? = null, + actionable: context(TimeDistribution) () -> Actionable = { makeReaction(contextOf>(), null) }, + block: context(Reaction) ActionableContext.() -> Unit = { } + ) = program(makeTimeDistribution(timeDistribution), actionable, block) + + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) + fun program(timeDistribution: Any? = null, actionable: Actionable, block: context(Reaction) ActionableContext.() -> Unit = { }) = + program(makeTimeDistribution(timeDistribution), actionable, block) + + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) + fun program(timeDistribution: TimeDistribution, descriptor: String? = null, block: context(Reaction) ActionableContext.() -> Unit = { }) = + program(timeDistribution, makeReaction(timeDistribution, descriptor), block) + + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) + fun program(timeDistribution: Any? = null, descriptor: String? = null, block: context(Reaction) ActionableContext.() -> Unit = { }) { + val timeDistribution = incarnation.createTimeDistribution(randomGenerator, environment, node, timeDistribution) + program(timeDistribution, makeReaction(timeDistribution, descriptor), block) + } + + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) + fun program(descriptor: String, block: context(Reaction) ActionableContext.() -> Unit = { }) = + program(timeDistribution = null, descriptor, block) + + fun contents(block: context(Incarnation) ContentContext.() -> Unit) + + private companion object { + + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) + fun > makeTimeDistribution(parameter: Any? = null) = incarnation.createTimeDistribution( + randomGenerator, + environment, + node, + parameter, + ) + + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) + fun > makeReaction(timeDistribution: TimeDistribution, descriptor: String?) = incarnation.createReaction( + randomGenerator, + environment, + node, + timeDistribution, + null, + ) + } +} + +interface DeploymentsContext> { + fun deploy(deployment: Deployment

, block: context(RandomGenerator, Node, P) DeploymentContext.() -> Unit = {}) +} + +interface TerminatorsContext> { + operator fun TerminationPredicate.unaryMinus() + @Suppress("UNCHECKED_CAST") + operator fun TerminationPredicate.unaryMinus() = (this as TerminationPredicate).unaryMinus() + @Suppress("UNCHECKED_CAST") + operator fun TerminationPredicate<*, P>.unaryMinus() = (this as TerminationPredicate).unaryMinus() + @Suppress("UNCHECKED_CAST") + operator fun TerminationPredicate<*, *>.unaryMinus() = (this as TerminationPredicate).unaryMinus() +} + +interface EnvironmentContext> { + fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) + fun monitor(monitor: OutputMonitor) + fun networkModel(model: LinkingRule) + fun terminator(terminator: TerminationPredicate) +} + +interface SimulationContext> { + fun > environment(environment: E, block: context(E) EnvironmentContext.() -> Unit) + fun scenarioRandomGenerator(randomGenerator: RandomGenerator) + fun scenarioSeed(seed: Long) + fun simulationRandomGenerator(randomGenerator: RandomGenerator) + fun simulationSeed(seed: Long) +} + +operator fun PositionBasedFilter<*>.contains(position: Position<*>): Boolean = contains(position) + +context(_: Incarnation) +fun SimulationContext.environment(block: context(Continuous2DEnvironment) EnvironmentContext.() -> Unit) = + environment(continuous2DEnvironment(), block) + +fun , I : Incarnation> simulation(incarnation: I, block: context(I) SimulationContext.() -> Unit): Unit = TODO() + +fun > simulationOnMap(incarnation: I, block: context(I) SimulationContext.() -> Unit): Unit = simulation(incarnation, block) + +fun > simulation2D(incarnation: I, block: context(I) SimulationContext.() -> Unit) = simulation(incarnation, block) + +fun main() { + simulation2D(SAPEREIncarnation()) { + environment { + monitor(SimpleMonitor()) + } + } + simulationOnMap(SAPEREIncarnation()){ + environment(oSMEnvironment( "vcm.pbf", false)) { + terminator(StableForSteps(5, 100)) + deployments { + val gps = FromGPSTrace( + 7, + "gpsTrace", + true, + "AlignToSimulationTime", + ) + deploy(gps) { + program( + timeDistribution = 15, + actionable = { event() } + ) { + action( + reproduceGPSTrace( + "gpsTrace", + true, + "AlignToSimulationTime", + ) + ) + } + } + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + deploy(makePerturbedGridForTesting()) { + if (position in Rectangle(-0.5, -0.5, 1.0, 1.0)) { + contents { + - "token, 0, []" + } + } + program( + DiracComb(0.5), + "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" + ) + program("{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}") + } + } + } + } + simulation2D(ProtelisIncarnation()) { + environment { + deployments { + deploy(point(1.5, 0.5)) { + program( + timeDistribution = JaktaTimeDistribution( + sense = weibullTime(1.0, 1.0), + deliberate = DiracComb(0.1), + act = exponentialTime(1.0), + ), + descriptor = "1 + 1" + ) + } + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + val token = "token" + deploy(makePerturbedGridForTesting()) { + contents { + if (position in Rectangle(-0.5, -0.5, 1.0, 1.0)) { + - token + } + } + program(1, "{token} --> {firing}") + program( "{firing} --> +{token}") + } + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + val hello = "hello" + deploy(makePerturbedGridForTesting()) { + contents { + -hello + if (position in Rectangle(-1.0, -1.0, 2.0, 2.0)) { + - "token" + } + } + } + } + } + } + simulationOnMap(ProtelisIncarnation()) { + environment(oSMEnvironment( "vcm.pbf", false)) { + terminators { + -StableForSteps(5, 100) + } + deployments { + deploy(FromGPSTrace(7, "gpsTrace", true, "AlignToSimulationTime")) { + program(timeDistribution = 15) { + action { + reproduceGPSTrace( + "gpsTrace", + true, + "AlignToSimulationTime", + ) + } + } + } + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + deployments { + val p = point(0.0, 0.0) + deploy(p) + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(5.0)) + deployments { + deploy(point(0.0, 0.0)) + deploy(point(0.0, 1.0)) + } + } + } + simulation2D(SAPEREIncarnation()) { + simulationSeed(10L) + scenarioSeed(20L) + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + deploy( + circle( + 10, + 0.0, + 0.0, + 10.0, + ), + ) + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + val grid = grid( + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.25, + 0.0, + 0.0, + ) + deploy(grid) + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + val hello = "hello" + deploy(DslLoaderFunctions.makePerturbedGridForTesting()) { + contents { + -hello + } + } + } + } + } +} + +context(_: RandomGenerator, _: Environment<*, Euclidean2DPosition>) +fun makePerturbedGridForTesting() = grid( + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.25, + 0.1, + 0.1, +) + diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt index 2e7993b53b..68a4486cbf 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt @@ -22,6 +22,7 @@ import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition +import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.actions.brownianMove import it.unibo.alchemist.model.deployments.Circle @@ -32,11 +33,14 @@ import it.unibo.alchemist.model.deployments.grid import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.deployments.polygon import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.environments.Euclidean2DEnvironment +import it.unibo.alchemist.model.environments.continuous2DEnvironment import it.unibo.alchemist.model.incarnations.ProtelisIncarnation import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.layers.StepLayer import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.maps.actions.ReproduceGPSTrace +import it.unibo.alchemist.model.maps.actions.reproduceGPSTrace import it.unibo.alchemist.model.maps.deployments.FromGPSTrace import it.unibo.alchemist.model.maps.environments.OSMEnvironment import it.unibo.alchemist.model.maps.environments.oSMEnvironment @@ -58,20 +62,16 @@ import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator object DslLoaderFunctions { - fun test01Nodes(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { - networkModel = ConnectWithinDistance(5.0) - deployments { - deploy(point(0.0, 0.0)) - deploy(Point(ctx.environment, 0.0, 1.0)) - } + fun test01Nodes(): Loader = simulation(SAPEREIncarnation()) { + networkModel = ConnectWithinDistance(5.0) + deployments { + deploy(point(0.0, 0.0)) + deploy(point(0.0, 1.0)) } } fun test02ManyNodes(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { + return simulation(SAPEREIncarnation()) { seeds { simulation(10L) scenario(20L) @@ -90,8 +90,7 @@ object DslLoaderFunctions { } } fun test03Grid(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { + return simulation(SAPEREIncarnation()) { networkModel = ConnectWithinDistance(0.5) deployments { val grid = grid( @@ -120,8 +119,7 @@ object DslLoaderFunctions { 0.1, ) fun test05Content(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { + return simulation(SAPEREIncarnation()) { networkModel = ConnectWithinDistance(0.5) deployments { val hello = "hello" @@ -135,8 +133,7 @@ object DslLoaderFunctions { } } fun test06ContentFiltered(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { + return simulation(SAPEREIncarnation()) { networkModel = ConnectWithinDistance(0.5) deployments { val hello = "hello" @@ -153,8 +150,7 @@ object DslLoaderFunctions { } fun test07Programs(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { + return simulation(SAPEREIncarnation()) { networkModel = ConnectWithinDistance(0.5) deployments { val token = "token" @@ -175,7 +171,7 @@ object DslLoaderFunctions { } } } - fun test08ProtelisPrograms(): Loader = simulation(ProtelisIncarnation()) { + fun test08ProtelisPrograms(): Loader = simulation(ProtelisIncarnation()) { deployments { deploy(point(1.5, 0.5)) { programs { @@ -195,8 +191,7 @@ object DslLoaderFunctions { } } fun test09TimeDistribution(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { + return simulation(SAPEREIncarnation()) { networkModel = ConnectWithinDistance(0.5) deployments { deploy(makePerturbedGridForTesting()) { @@ -218,8 +213,8 @@ object DslLoaderFunctions { } fun test10Environment(): Loader { val incarnation = SAPEREIncarnation() - val env = OSMEnvironment(incarnation, "vcm.pbf", false) - return simulation(incarnation, { env }) { + return simulation(incarnation) { + environment { oSMEnvironment( "vcm.pbf", false) } terminators { +StableForSteps(5, 100) } @@ -236,10 +231,7 @@ object DslLoaderFunctions { timeDistribution("15") reaction = Event(node, timeDistribution) addAction { - ReproduceGPSTrace( - env, - node, - reaction, + reproduceGPSTrace( "gpsTrace", true, "AlignToSimulationTime", @@ -252,8 +244,7 @@ object DslLoaderFunctions { } } fun test11monitors(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { + return simulation(SAPEREIncarnation()) { monitors { +SimpleMonitor, Euclidean2DPosition>() } @@ -349,8 +340,7 @@ object DslLoaderFunctions { } fun test16ProgramsFilters(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { + return simulation(SAPEREIncarnation()) { networkModel = ConnectWithinDistance(0.5) deployments { val token = "token" @@ -372,8 +362,7 @@ object DslLoaderFunctions { } } fun test17CustomNodes(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { + return simulation(SAPEREIncarnation()) { deployments { deploy( circle( diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt index 861289db92..bc80b7524f 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -11,6 +11,7 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.sapere.molecules.LsaMolecule import org.junit.jupiter.api.Test @@ -21,7 +22,7 @@ class TestContents { fun testAll() { val loader = simulation(SAPEREIncarnation()) { deployments { - deploy(Point(ctx.environment, 0.0, 0.0)) { + deploy(point(0.0, 0.0)) { all { molecule = "test" concentration = listOf(LsaMolecule("1")) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index 40f2109c4e..fc9840aaf1 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -13,6 +13,7 @@ import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.model.deployments.Grid import it.unibo.alchemist.model.deployments.Point import it.unibo.alchemist.model.deployments.grid +import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import org.junit.jupiter.api.Test @@ -22,7 +23,7 @@ class TestDeployments { fun testDeployments() { val loader = simulation(SAPEREIncarnation()) { deployments { - val p = Point(ctx.environment, 0.0, 0.0) + val p = point(0.0, 0.0) deploy(p) } } @@ -34,9 +35,9 @@ class TestDeployments { fun testMultipleDeployments() { val loader = simulation(SAPEREIncarnation()) { deployments { - val point = Point(ctx.environment, 0.0, 0.0) + val point = point(0.0, 0.0) deploy(point) - deploy(Point(ctx.environment, 1.0, 1.0)) + deploy(point(1.0, 1.0)) } } From 8cb6e6f90e5fa44067b71847507f078c6fff15d1 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 29 Jan 2026 19:48:12 +0100 Subject: [PATCH 154/196] refactor: improve program function signature and update StableForSteps type parameters --- .../alchemist/model/terminators/StableForSteps.kt | 10 +++++----- alchemist-loading/src/test/kotlin/DSL2.kt | 10 ++++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/terminators/StableForSteps.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/terminators/StableForSteps.kt index be8a7074e8..8b4696ac5a 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/terminators/StableForSteps.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/terminators/StableForSteps.kt @@ -43,10 +43,10 @@ import java.util.function.Predicate * @param equalIntervals The amount of [checkInterval] intervals that need to pass * (during which the environment doesn't change) for [test] to return true */ -data class StableForSteps(private val checkInterval: Long, private val equalIntervals: Long) : - TerminationPredicate> { +data class StableForSteps>(private val checkInterval: Long, private val equalIntervals: Long) : + TerminationPredicate { private var success: Long = 0 - private var positions: Map, Position<*>> = emptyMap() + private var positions: Map, P> = emptyMap() private var contents = makeTable(0) init { @@ -55,7 +55,7 @@ data class StableForSteps(private val checkInterval: Long, private val } } - override fun invoke(environment: Environment>): Boolean { + override fun invoke(environment: Environment): Boolean { if (environment.simulation.step % checkInterval == 0L) { val newPositions = environment.associateBy({ it }, { environment.getPosition(it) }) val newContents = makeTable(environment.nodeCount) @@ -72,7 +72,7 @@ data class StableForSteps(private val checkInterval: Long, private val } private companion object { - private fun makeTable(size: Int): Table, Molecule, T> = + private fun makeTable(size: Int): Table, Molecule, T> = Tables.newCustomTable(Maps.newLinkedHashMapWithExpectedSize, Map>(size)) { Maps.newLinkedHashMapWithExpectedSize(size) } diff --git a/alchemist-loading/src/test/kotlin/DSL2.kt b/alchemist-loading/src/test/kotlin/DSL2.kt index 4d2ce41e07..9d0bfe4b12 100644 --- a/alchemist-loading/src/test/kotlin/DSL2.kt +++ b/alchemist-loading/src/test/kotlin/DSL2.kt @@ -103,7 +103,11 @@ interface DeploymentContext> { program(timeDistribution, makeReaction(timeDistribution, descriptor), block) context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program(timeDistribution: Any? = null, descriptor: String? = null, block: context(Reaction) ActionableContext.() -> Unit = { }) { + fun program( + timeDistribution: Any? = null, + descriptor: String? = null, + block: context(Reaction + ) ActionableContext.() -> Unit = { }) { val timeDistribution = incarnation.createTimeDistribution(randomGenerator, environment, node, timeDistribution) program(timeDistribution, makeReaction(timeDistribution, descriptor), block) } @@ -279,9 +283,7 @@ fun main() { } simulationOnMap(ProtelisIncarnation()) { environment(oSMEnvironment( "vcm.pbf", false)) { - terminators { - -StableForSteps(5, 100) - } + terminator(StableForSteps(5, 100)) deployments { deploy(FromGPSTrace(7, "gpsTrace", true, "AlignToSimulationTime")) { program(timeDistribution = 15) { From 74aa4c141cd996303f7392220feaca8ae7e1cc24 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sat, 31 Jan 2026 21:46:44 +0100 Subject: [PATCH 155/196] refactor: simplify time distribution handling and improve program context usage --- alchemist-loading/src/test/kotlin/DSL2.kt | 115 +++++++++++----------- 1 file changed, 55 insertions(+), 60 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/DSL2.kt b/alchemist-loading/src/test/kotlin/DSL2.kt index 9d0bfe4b12..f0e2a9c8f8 100644 --- a/alchemist-loading/src/test/kotlin/DSL2.kt +++ b/alchemist-loading/src/test/kotlin/DSL2.kt @@ -10,9 +10,7 @@ package attempt import another.location.SimpleMonitor -import com.lowagie.tools.BuildTutorial.action import it.unibo.alchemist.boundary.OutputMonitor -import it.unibo.alchemist.boundary.dsl.Dsl import it.unibo.alchemist.dsl.DslLoaderFunctions import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution import it.unibo.alchemist.model.Action @@ -28,7 +26,6 @@ import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter import it.unibo.alchemist.model.Reaction import it.unibo.alchemist.model.TerminationPredicate -import it.unibo.alchemist.model.Time import it.unibo.alchemist.model.TimeDistribution import it.unibo.alchemist.model.deployments.circle import it.unibo.alchemist.model.deployments.grid @@ -44,7 +41,6 @@ import it.unibo.alchemist.model.maps.environments.oSMEnvironment import it.unibo.alchemist.model.positionfilters.Rectangle import it.unibo.alchemist.model.positions.Euclidean2DPosition import it.unibo.alchemist.model.reactions.event -import it.unibo.alchemist.model.sapere.ILsaMolecule import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.timedistributions.DiracComb import it.unibo.alchemist.model.timedistributions.exponentialTime @@ -73,48 +69,45 @@ interface ContentContext { } -interface DeploymentContext> { +interface TimeDistributionContext> { - val position: P + context(timeDistribution: TimeDistribution) + val timeDistribution: TimeDistribution get() = timeDistribution - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program(timeDistribution: TimeDistribution, actionable: Actionable, block: context(Reaction) ActionableContext.() -> Unit = { }) + fun > program(actionable: A, block: context(A) ActionableContext.() -> Unit = { }) - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program( - timeDistribution: TimeDistribution, - actionable: context(TimeDistribution) () -> Actionable = { makeReaction(timeDistribution, null) }, - block: context(Reaction) ActionableContext.() -> Unit = { } - ) = program(timeDistribution, context(timeDistribution) { actionable() }, block) + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node, timeDistribution: TimeDistribution) + fun program(program: String?, block: context(Reaction) ActionableContext.() -> Unit = { }) = + program( + incarnation.createReaction(randomGenerator, environment, node, timeDistribution, program), + block + ) +} - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program( - timeDistribution: Any? = null, - actionable: context(TimeDistribution) () -> Actionable = { makeReaction(contextOf>(), null) }, - block: context(Reaction) ActionableContext.() -> Unit = { } - ) = program(makeTimeDistribution(timeDistribution), actionable, block) +interface DeploymentContext> { - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program(timeDistribution: Any? = null, actionable: Actionable, block: context(Reaction) ActionableContext.() -> Unit = { }) = - program(makeTimeDistribution(timeDistribution), actionable, block) + val position: P - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program(timeDistribution: TimeDistribution, descriptor: String? = null, block: context(Reaction) ActionableContext.() -> Unit = { }) = - program(timeDistribution, makeReaction(timeDistribution, descriptor), block) + fun > timeDistribution( + timeDistribution: TimeDistributionType, + block: context(TimeDistributionType) TimeDistributionContext.() -> Unit + ) + @Suppress("UNCHECKED_CAST") context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program( - timeDistribution: Any? = null, - descriptor: String? = null, - block: context(Reaction - ) ActionableContext.() -> Unit = { }) { - val timeDistribution = incarnation.createTimeDistribution(randomGenerator, environment, node, timeDistribution) - program(timeDistribution, makeReaction(timeDistribution, descriptor), block) - } + fun withTimeDistribution( + parameter: Any? = null, + block: context(TimeDistribution) TimeDistributionContext.() -> Unit + ) = timeDistribution>( + parameter as? TimeDistribution ?: makeTimeDistribution(parameter), + block + ) context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program(descriptor: String, block: context(Reaction) ActionableContext.() -> Unit = { }) = - program(timeDistribution = null, descriptor, block) + fun program(timeDistribution: Any? = null, program: String? = null, block: context(Reaction) ActionableContext.() -> Unit = { }) = + withTimeDistribution(timeDistribution) { + program(program, block) + } fun contents(block: context(Incarnation) ContentContext.() -> Unit) @@ -128,8 +121,8 @@ interface DeploymentContext> { parameter, ) - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun > makeReaction(timeDistribution: TimeDistribution, descriptor: String?) = incarnation.createReaction( + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node, timeDistribution: TimeDistribution) + fun > makeReaction(descriptor: String?) = incarnation.createReaction( randomGenerator, environment, node, @@ -197,17 +190,16 @@ fun main() { "AlignToSimulationTime", ) deploy(gps) { - program( - timeDistribution = 15, - actionable = { event() } - ) { - action( - reproduceGPSTrace( - "gpsTrace", - true, - "AlignToSimulationTime", + withTimeDistribution(15) { + program(event()) { + action( + reproduceGPSTrace( + "gpsTrace", + true, + "AlignToSimulationTime", + ) ) - ) + } } } } @@ -223,10 +215,9 @@ fun main() { - "token, 0, []" } } - program( - DiracComb(0.5), - "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" - ) + timeDistribution(DiracComb(0.5)) { + program("{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}") + } program("{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}") } } @@ -236,14 +227,15 @@ fun main() { environment { deployments { deploy(point(1.5, 0.5)) { - program( - timeDistribution = JaktaTimeDistribution( + timeDistribution( + JaktaTimeDistribution( sense = weibullTime(1.0, 1.0), deliberate = DiracComb(0.1), act = exponentialTime(1.0), - ), - descriptor = "1 + 1" - ) + ) + ) { + program("1 + 1") + } } } } @@ -259,7 +251,10 @@ fun main() { - token } } - program(1, "{token} --> {firing}") + program( + timeDistribution = 1, + "{token} --> {firing}" + ) program( "{firing} --> +{token}") } } @@ -287,13 +282,13 @@ fun main() { deployments { deploy(FromGPSTrace(7, "gpsTrace", true, "AlignToSimulationTime")) { program(timeDistribution = 15) { - action { + action( reproduceGPSTrace( "gpsTrace", true, "AlignToSimulationTime", ) - } + ) } } } From c5c6993f93a041349e8b70579ff0b50b8dae56e1 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 5 Feb 2026 19:43:53 +0100 Subject: [PATCH 156/196] refactor: enhance global program handling and add layer support in simulation context --- alchemist-loading/src/test/kotlin/DSL2.kt | 48 ++++++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/DSL2.kt b/alchemist-loading/src/test/kotlin/DSL2.kt index f0e2a9c8f8..4c30aed54c 100644 --- a/alchemist-loading/src/test/kotlin/DSL2.kt +++ b/alchemist-loading/src/test/kotlin/DSL2.kt @@ -11,14 +11,18 @@ package attempt import another.location.SimpleMonitor import it.unibo.alchemist.boundary.OutputMonitor +import it.unibo.alchemist.boundary.dsl.Dsl import it.unibo.alchemist.dsl.DslLoaderFunctions import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable +import it.unibo.alchemist.model.Condition import it.unibo.alchemist.model.Deployment import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition +import it.unibo.alchemist.model.GlobalReaction import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Molecule import it.unibo.alchemist.model.Node @@ -34,21 +38,25 @@ import it.unibo.alchemist.model.environments.Continuous2DEnvironment import it.unibo.alchemist.model.environments.continuous2DEnvironment import it.unibo.alchemist.model.incarnations.ProtelisIncarnation import it.unibo.alchemist.model.incarnations.SAPEREIncarnation +import it.unibo.alchemist.model.layers.StepLayer import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import it.unibo.alchemist.model.maps.actions.reproduceGPSTrace import it.unibo.alchemist.model.maps.deployments.FromGPSTrace import it.unibo.alchemist.model.maps.environments.oSMEnvironment import it.unibo.alchemist.model.positionfilters.Rectangle import it.unibo.alchemist.model.positions.Euclidean2DPosition +import it.unibo.alchemist.model.reactions.Event import it.unibo.alchemist.model.reactions.event import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.timedistributions.DiracComb import it.unibo.alchemist.model.timedistributions.exponentialTime import it.unibo.alchemist.model.timedistributions.weibullTime +import it.unibo.alchemist.test.globalTestReaction import org.apache.commons.math3.random.RandomGenerator interface ActionableContext { fun action(action: Action) + fun condition(condition: Condition) } interface ContentContext { @@ -138,16 +146,16 @@ interface DeploymentsContext> { interface TerminatorsContext> { operator fun TerminationPredicate.unaryMinus() - @Suppress("UNCHECKED_CAST") - operator fun TerminationPredicate.unaryMinus() = (this as TerminationPredicate).unaryMinus() - @Suppress("UNCHECKED_CAST") - operator fun TerminationPredicate<*, P>.unaryMinus() = (this as TerminationPredicate).unaryMinus() - @Suppress("UNCHECKED_CAST") - operator fun TerminationPredicate<*, *>.unaryMinus() = (this as TerminationPredicate).unaryMinus() } interface EnvironmentContext> { fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) + fun globalProgram(timeDistribution: TimeDistribution, globalReaction: GlobalReaction, block: context(GlobalReaction) ActionableContext.() -> Unit = {}) + + fun layer(molecule: Molecule, layer: Layer) + + context(incarnation: Incarnation) + fun layer(molecule: String? = null, layer: Layer) = layer(incarnation.createMolecule(molecule), layer) fun monitor(monitor: OutputMonitor) fun networkModel(model: LinkingRule) fun terminator(terminator: TerminationPredicate) @@ -174,6 +182,34 @@ fun > simulationOnMap(incarnation: I, block: fun > simulation2D(incarnation: I, block: context(I) SimulationContext.() -> Unit) = simulation(incarnation, block) fun main() { + simulation2D(ProtelisIncarnation()) { + environment { + globalProgram(DiracComb(1.0), globalTestReaction(DiracComb(1.0))) + } + } + simulation2D(ProtelisIncarnation()) { + environment { + layer("A", StepLayer(2.0, 2.0, 100, 0)) + layer("B", StepLayer(-2.0, -2.0, 0, 100)) + deployments { + deploy( + grid( + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.1, + 0.1, + ), + ) { + contents { + - "a" + } + } + } + } + } simulation2D(SAPEREIncarnation()) { environment { monitor(SimpleMonitor()) From f79ec94a7550d6b8844d0d0c8b8b071770dfe444 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 5 Feb 2026 21:55:37 +0100 Subject: [PATCH 157/196] refactor: rename exporter classes and update copyright year --- .../it/unibo/alchemist/boundary/Variable.java | 3 +- .../boundary/dsl/model/PropertiesContext.kt | 36 --------- ... => AbstractAggregatingDoubleExtractor.kt} | 6 +- ...Exporter.kt => AbstractDoubleExtractor.kt} | 2 +- .../boundary/extractors/ExecutionTime.kt | 4 +- .../boundary/extractors/MeanSquaredError.kt | 4 +- .../boundary/extractors/MoleculeReader.kt | 4 +- .../boundary/extractors/NodeDegree.kt | 11 ++- .../boundary/extractors/NodesPositions.kt | 4 +- .../extractors/SubnetworksDiameter.kt | 11 ++- .../alchemist/boundary/extractors/Time.kt | 2 +- alchemist-loading/src/test/kotlin/DSL2.kt | 74 +++++++++++++++++-- 12 files changed, 103 insertions(+), 58 deletions(-) rename alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/{AbstractAggregatingDoubleExporter.kt => AbstractAggregatingDoubleExtractor.kt} (95%) rename alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/{AbstractDoubleExporter.kt => AbstractDoubleExtractor.kt} (97%) diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/Variable.java b/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/Variable.java index 44bccc1cd5..dcb1774bd5 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/Variable.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/Variable.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -44,5 +44,4 @@ default long steps() { * @return all values of this variable as {@link Stream}. */ Stream stream(); - } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt index 8817ff430f..3ac554109b 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt @@ -77,39 +77,3 @@ interface PropertiesContext> { */ fun all(block: context(Environment, Node) PropertyContext.() -> Unit) } - -/** - * Context interface for configuring properties for a specific node. - * - * This context is used within [PropertiesContext] blocks to add properties to nodes. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - * - * @see [PropertiesContext] for the parent context - * @see [NodeProperty] for the property interface - */ -@AlchemistDsl -interface PropertyContext> { - /** - * The properties context this property context belongs to. - */ - val ctx: PropertiesContext - - /** - * The optional position filter applied to this property context. - */ - val filter: PositionBasedFilter

? - - /** - * The node this property context is configuring. - */ - val node: Node - - /** - * Adds a property to the node. - * - * @see [NodeProperty] - */ - operator fun NodeProperty.unaryPlus() -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractAggregatingDoubleExporter.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractAggregatingDoubleExtractor.kt similarity index 95% rename from alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractAggregatingDoubleExporter.kt rename to alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractAggregatingDoubleExtractor.kt index acb4c52896..ce4fbd119a 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractAggregatingDoubleExporter.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractAggregatingDoubleExtractor.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -25,13 +25,13 @@ import org.apache.commons.math3.stat.descriptive.UnivariateStatistic * extracts data from the environment, filters it, and then aggregates it. * Available aggregators can be found at this [site](http://bit.ly/40MWWvt). */ -abstract class AbstractAggregatingDoubleExporter +abstract class AbstractAggregatingDoubleExtractor @JvmOverloads constructor( private val filter: ExportFilter = CommonFilters.NOFILTER.filteringPolicy, aggregatorNames: List, precision: Int? = null, -) : AbstractDoubleExporter(precision) { +) : AbstractDoubleExtractor(precision) { constructor( filter: String?, aggregatorNames: List, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractDoubleExporter.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractDoubleExtractor.kt similarity index 97% rename from alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractDoubleExporter.kt rename to alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractDoubleExtractor.kt index 819ae8f9d0..bedab00481 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractDoubleExporter.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/AbstractDoubleExtractor.kt @@ -20,7 +20,7 @@ import java.util.Locale * Provided a [precision] representing the significant digits, formats doubles accordingly, using [Locale.ENGLISH]. * If `null` is provided, returns the default conversion to string. */ -abstract class AbstractDoubleExporter +abstract class AbstractDoubleExtractor @JvmOverloads constructor(val precision: Int? = null) : Extractor { init { diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/ExecutionTime.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/ExecutionTime.kt index 057d54e923..9e8a38cdf6 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/ExecutionTime.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/ExecutionTime.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -19,7 +19,7 @@ import it.unibo.alchemist.model.Time */ class ExecutionTime @JvmOverloads -constructor(precision: Int? = null) : AbstractDoubleExporter(precision) { +constructor(precision: Int? = null) : AbstractDoubleExtractor(precision) { private companion object { private const val NANOS_TO_SEC: Double = 1e9 } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MeanSquaredError.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MeanSquaredError.kt index 7ff3b31ad7..adaeb0a9dd 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MeanSquaredError.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MeanSquaredError.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -37,7 +37,7 @@ constructor( localValueMolecule: String, localValueProperty: String = "", precision: Int? = null, -) : AbstractDoubleExporter(precision) { +) : AbstractDoubleExtractor(precision) { constructor( incarnation: Incarnation, localCorrectValueMolecule: String, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt index 3fbae31a28..c112b62a54 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/MoleculeReader.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -43,7 +43,7 @@ constructor( private val filter: ExportFilter, aggregatorNames: List, precision: Int? = null, -) : AbstractAggregatingDoubleExporter(filter, aggregatorNames, precision) { +) : AbstractAggregatingDoubleExtractor(filter, aggregatorNames, precision) { private companion object { private const val SHORT_NAME_MAX_LENGTH = 5 } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NodeDegree.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NodeDegree.kt index 2dce769345..6004eb8844 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NodeDegree.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NodeDegree.kt @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.boundary.extractors import it.unibo.alchemist.boundary.ExportFilter @@ -14,7 +23,7 @@ import it.unibo.alchemist.model.Time class NodeDegree @JvmOverloads constructor(filter: ExportFilter, aggregators: List, precision: Int = 2) : - AbstractAggregatingDoubleExporter(filter, aggregators, precision) { + AbstractAggregatingDoubleExtractor(filter, aggregators, precision) { override val columnName: String = NAME override fun getData( diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NodesPositions.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NodesPositions.kt index a683bf29c5..f63ec8d5a4 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NodesPositions.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NodesPositions.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2024, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -20,7 +20,7 @@ import it.unibo.alchemist.model.Time * * Note: this exporter is not designed to handle changes in the environment topology like node removal or addition. */ -class NodesPositions>(private val environment: Environment) : AbstractDoubleExporter() { +class NodesPositions>(private val environment: Environment) : AbstractDoubleExtractor() { override val columnNames: List by lazy { (0 until environment.nodeCount).flatMap { nodeId -> (0 until environment.dimensions).map { dimensionIndex -> diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/SubnetworksDiameter.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/SubnetworksDiameter.kt index 158d8c95fd..b7a48b80e0 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/SubnetworksDiameter.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/SubnetworksDiameter.kt @@ -1,3 +1,12 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + package it.unibo.alchemist.boundary.extractors import it.unibo.alchemist.boundary.ExportFilter @@ -18,7 +27,7 @@ constructor( filter: ExportFilter, aggregators: List, precision: Int = 2, -) : AbstractAggregatingDoubleExporter(filter, aggregators, precision) { +) : AbstractAggregatingDoubleExtractor(filter, aggregators, precision) { private companion object { private const val NAME: String = "subnetworks-diameter" } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/Time.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/Time.kt index ca48d37500..51cfd1b2e1 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/Time.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/Time.kt @@ -18,7 +18,7 @@ import it.unibo.alchemist.model.Time */ class Time @JvmOverloads -constructor(precision: Int? = null) : AbstractDoubleExporter(precision) { +constructor(precision: Int? = null) : AbstractDoubleExtractor(precision) { override val columnNames = listOf(NAME) override fun extractData( diff --git a/alchemist-loading/src/test/kotlin/DSL2.kt b/alchemist-loading/src/test/kotlin/DSL2.kt index 4c30aed54c..7bf6b442e2 100644 --- a/alchemist-loading/src/test/kotlin/DSL2.kt +++ b/alchemist-loading/src/test/kotlin/DSL2.kt @@ -10,9 +10,18 @@ package attempt import another.location.SimpleMonitor +import it.unibo.alchemist.boundary.Exporter +import it.unibo.alchemist.boundary.Extractor import it.unibo.alchemist.boundary.OutputMonitor -import it.unibo.alchemist.boundary.dsl.Dsl +import it.unibo.alchemist.boundary.Variable +import it.unibo.alchemist.boundary.exporters.CSVExporter +import it.unibo.alchemist.boundary.exportfilters.CommonFilters +import it.unibo.alchemist.boundary.extractors.Time +import it.unibo.alchemist.boundary.extractors.moleculeReader +import it.unibo.alchemist.boundary.variables.GeometricVariable +import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.dsl.DslLoaderFunctions +import it.unibo.alchemist.dsl.DslLoaderFunctions.makePerturbedGridForTesting import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable @@ -45,13 +54,17 @@ import it.unibo.alchemist.model.maps.deployments.FromGPSTrace import it.unibo.alchemist.model.maps.environments.oSMEnvironment import it.unibo.alchemist.model.positionfilters.Rectangle import it.unibo.alchemist.model.positions.Euclidean2DPosition -import it.unibo.alchemist.model.reactions.Event import it.unibo.alchemist.model.reactions.event +import it.unibo.alchemist.model.terminators.AfterTime import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.timedistributions.DiracComb import it.unibo.alchemist.model.timedistributions.exponentialTime import it.unibo.alchemist.model.timedistributions.weibullTime +import it.unibo.alchemist.model.times.DoubleTime import it.unibo.alchemist.test.globalTestReaction +import java.io.Serializable +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty import org.apache.commons.math3.random.RandomGenerator interface ActionableContext { @@ -112,7 +125,7 @@ interface DeploymentContext> { ) context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program(timeDistribution: Any? = null, program: String? = null, block: context(Reaction) ActionableContext.() -> Unit = { }) = + fun program(program: String? = null, timeDistribution: Any? = null, block: context(Reaction) ActionableContext.() -> Unit = { }) = withTimeDistribution(timeDistribution) { program(program, block) } @@ -161,12 +174,26 @@ interface EnvironmentContext> { fun terminator(terminator: TerminationPredicate) } +interface ExporterContext> { + operator fun Extractor<*>.unaryMinus() +} + +interface VariableProvider { + operator fun provideDelegate( + thisRef: Any?, + property: KProperty<*>, + ): ReadOnlyProperty +} + interface SimulationContext> { fun > environment(environment: E, block: context(E) EnvironmentContext.() -> Unit) + fun exportWith(exporter: Exporter, block: ExporterContext.() -> Unit) fun scenarioRandomGenerator(randomGenerator: RandomGenerator) fun scenarioSeed(seed: Long) fun simulationRandomGenerator(randomGenerator: RandomGenerator) fun simulationSeed(seed: Long) + + fun variable(variable: Variable): VariableProvider } operator fun PositionBasedFilter<*>.contains(position: Position<*>): Boolean = contains(position) @@ -182,6 +209,43 @@ fun > simulationOnMap(incarnation: I, block: fun > simulation2D(incarnation: I, block: context(I) SimulationContext.() -> Unit) = simulation(incarnation, block) fun main() { + simulation2D(SAPEREIncarnation()) { + val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) + val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + + environment { + val mSize = -size + val sourceStart = mSize / 10.0 + val sourceSize = size / 5.0 + terminator(AfterTime(DoubleTime(1.0))) + networkModel(ConnectWithinDistance(0.5)) + deployments { + deploy(makePerturbedGridForTesting()) { + if (position in Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { + contents { + - "token, 0, []" + } + } + program( + "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}", + rate + ) + program("{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}") + } + } + } + } + simulation(ProtelisIncarnation()) { + exportWith(CSVExporter("test_export_interval", 4.0)) { + - Time() + - moleculeReader( + "default_module:default_program", + null, + CommonFilters.NOFILTER.filteringPolicy, + emptyList(), + ) + } + } simulation2D(ProtelisIncarnation()) { environment { globalProgram(DiracComb(1.0), globalTestReaction(DiracComb(1.0))) @@ -288,8 +352,8 @@ fun main() { } } program( - timeDistribution = 1, - "{token} --> {firing}" + "{token} --> {firing}", + timeDistribution = 1 ) program( "{firing} --> +{token}") } From 95ef0b7c6a93dd2b363c75ae12532ade3cc72fa1 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 5 Feb 2026 22:47:24 +0100 Subject: [PATCH 158/196] implement node properties --- alchemist-loading/src/test/kotlin/DSL2.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/alchemist-loading/src/test/kotlin/DSL2.kt b/alchemist-loading/src/test/kotlin/DSL2.kt index 7bf6b442e2..768f80fbfc 100644 --- a/alchemist-loading/src/test/kotlin/DSL2.kt +++ b/alchemist-loading/src/test/kotlin/DSL2.kt @@ -35,6 +35,7 @@ import it.unibo.alchemist.model.Layer import it.unibo.alchemist.model.LinkingRule import it.unibo.alchemist.model.Molecule import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.NodeProperty import it.unibo.alchemist.model.Position import it.unibo.alchemist.model.PositionBasedFilter import it.unibo.alchemist.model.Reaction @@ -132,6 +133,8 @@ interface DeploymentContext> { fun contents(block: context(Incarnation) ContentContext.() -> Unit) + fun nodeProperty(property: NodeProperty) + private companion object { context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) From 263202b99a69d4de42fca97bdc6a425e5973d923 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Fri, 6 Feb 2026 18:04:35 +0100 Subject: [PATCH 159/196] begin implementation --- alchemist-loading/src/test/kotlin/DSL2.kt | 66 +++++++++++++++++------ 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/DSL2.kt b/alchemist-loading/src/test/kotlin/DSL2.kt index 768f80fbfc..ad68143888 100644 --- a/alchemist-loading/src/test/kotlin/DSL2.kt +++ b/alchemist-loading/src/test/kotlin/DSL2.kt @@ -69,24 +69,33 @@ import kotlin.reflect.KProperty import org.apache.commons.math3.random.RandomGenerator interface ActionableContext { - fun action(action: Action) - fun condition(condition: Condition) + context(actionable: Actionable) + fun action(action: Action) { + actionable.actions += action + } + context(actionable: Actionable) + fun condition(condition: Condition) { + actionable.conditions += condition + } } interface ContentContext { context(incarnation: Incarnation) - fun concentrationOf(origin: Any?) = incarnation.createConcentration(origin) + fun concentrationOf(origin: Any?): T = incarnation.createConcentration(origin) - operator fun Pair.unaryMinus() + context(node: Node) + operator fun Pair.unaryMinus() { + node.setConcentration(first, second) + } - context(incarnation: Incarnation) + context(incarnation: Incarnation, _: Node) operator fun Molecule.unaryMinus() = -Pair(this, incarnation.createConcentration()) - context(incarnation: Incarnation) + context(incarnation: Incarnation, _: Node) operator fun String.unaryMinus() = -Pair(incarnation.createMolecule(this), incarnation.createConcentration()) - context(incarnation: Incarnation) + context(incarnation: Incarnation, _: Node) operator fun Pair.unaryMinus() = -Pair(incarnation.createMolecule(first), second) } @@ -96,7 +105,13 @@ interface TimeDistributionContext> { context(timeDistribution: TimeDistribution) val timeDistribution: TimeDistribution get() = timeDistribution - fun > program(actionable: A, block: context(A) ActionableContext.() -> Unit = { }) + context(node: Node) + fun > program(reaction: R, block: context(R) ActionableContext.() -> Unit = { }) { + context(reaction) { + object : ActionableContext { }.block() + } + node.addReaction(reaction) + } context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node, timeDistribution: TimeDistribution) fun program(program: String?, block: context(Reaction) ActionableContext.() -> Unit = { }) = @@ -113,7 +128,11 @@ interface DeploymentContext> { fun > timeDistribution( timeDistribution: TimeDistributionType, block: context(TimeDistributionType) TimeDistributionContext.() -> Unit - ) + ) { + context(timeDistribution) { + object : TimeDistributionContext { }.block() + } + } @Suppress("UNCHECKED_CAST") context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) @@ -131,14 +150,20 @@ interface DeploymentContext> { program(program, block) } - fun contents(block: context(Incarnation) ContentContext.() -> Unit) + context(_: Incarnation, _: Node) + fun contents(block: context(Incarnation) ContentContext.() -> Unit) { + object : ContentContext { }.block() + } - fun nodeProperty(property: NodeProperty) + context(node: Node) + fun nodeProperty(property: NodeProperty) { + node.addProperty(property) + } private companion object { context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun > makeTimeDistribution(parameter: Any? = null) = incarnation.createTimeDistribution( + fun > makeTimeDistribution(parameter: Any? = null): TimeDistribution = incarnation.createTimeDistribution( randomGenerator, environment, node, @@ -146,7 +171,7 @@ interface DeploymentContext> { ) context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node, timeDistribution: TimeDistribution) - fun > makeReaction(descriptor: String?) = incarnation.createReaction( + fun > makeReaction(descriptor: String?): Reaction = incarnation.createReaction( randomGenerator, environment, node, @@ -157,7 +182,18 @@ interface DeploymentContext> { } interface DeploymentsContext> { - fun deploy(deployment: Deployment

, block: context(RandomGenerator, Node, P) DeploymentContext.() -> Unit = {}) + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment) + fun deploy(deployment: Deployment

, block: context(RandomGenerator, Node) DeploymentContext.() -> Unit = {}) { + deployment.forEach { position -> + val node: Node = incarnation.createNode(randomGenerator, environment, TODO()) + context(node) { + object : DeploymentContext { + override val position: P get() = position + }.block() + } + environment.addNode(node, position) + } + } } interface TerminatorsContext> { @@ -454,7 +490,7 @@ fun main() { networkModel(ConnectWithinDistance(0.5)) deployments { val hello = "hello" - deploy(DslLoaderFunctions.makePerturbedGridForTesting()) { + deploy(makePerturbedGridForTesting()) { contents { -hello } From 439de268beea8e30fe5b649a589056af82bf0309 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sat, 7 Feb 2026 23:01:57 +0100 Subject: [PATCH 160/196] refactor: enhance context handling and add support for launcher and monitor in simulation --- alchemist-loading/src/test/kotlin/DSL2.kt | 172 +++++++++++++++++----- 1 file changed, 136 insertions(+), 36 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/DSL2.kt b/alchemist-loading/src/test/kotlin/DSL2.kt index ad68143888..200e8dd7db 100644 --- a/alchemist-loading/src/test/kotlin/DSL2.kt +++ b/alchemist-loading/src/test/kotlin/DSL2.kt @@ -10,17 +10,21 @@ package attempt import another.location.SimpleMonitor +import it.unibo.alchemist.boundary.DependentVariable import it.unibo.alchemist.boundary.Exporter import it.unibo.alchemist.boundary.Extractor +import it.unibo.alchemist.boundary.Launcher +import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.Variable import it.unibo.alchemist.boundary.exporters.CSVExporter import it.unibo.alchemist.boundary.exportfilters.CommonFilters import it.unibo.alchemist.boundary.extractors.Time import it.unibo.alchemist.boundary.extractors.moleculeReader +import it.unibo.alchemist.boundary.launchers.DefaultLauncher import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable -import it.unibo.alchemist.dsl.DslLoaderFunctions +import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.dsl.DslLoaderFunctions.makePerturbedGridForTesting import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution import it.unibo.alchemist.model.Action @@ -49,7 +53,9 @@ import it.unibo.alchemist.model.environments.continuous2DEnvironment import it.unibo.alchemist.model.incarnations.ProtelisIncarnation import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.layers.StepLayer +import it.unibo.alchemist.model.linkingrules.CombinedLinkingRule import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance +import it.unibo.alchemist.model.linkingrules.NoLinks import it.unibo.alchemist.model.maps.actions.reproduceGPSTrace import it.unibo.alchemist.model.maps.deployments.FromGPSTrace import it.unibo.alchemist.model.maps.environments.oSMEnvironment @@ -66,37 +72,38 @@ import it.unibo.alchemist.test.globalTestReaction import java.io.Serializable import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty +import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator -interface ActionableContext { +object ActionableContext { context(actionable: Actionable) - fun action(action: Action) { + fun action(action: Action) { actionable.actions += action } context(actionable: Actionable) - fun condition(condition: Condition) { + fun condition(condition: Condition) { actionable.conditions += condition } } -interface ContentContext { +object ContentContext { context(incarnation: Incarnation) - fun concentrationOf(origin: Any?): T = incarnation.createConcentration(origin) + fun concentrationOf(origin: Any?): T = incarnation.createConcentration(origin) context(node: Node) - operator fun Pair.unaryMinus() { + operator fun Pair.unaryMinus() { node.setConcentration(first, second) } context(incarnation: Incarnation, _: Node) - operator fun Molecule.unaryMinus() = -Pair(this, incarnation.createConcentration()) + operator fun Molecule.unaryMinus() = -Pair(this, incarnation.createConcentration()) context(incarnation: Incarnation, _: Node) - operator fun String.unaryMinus() = -Pair(incarnation.createMolecule(this), incarnation.createConcentration()) + operator fun String.unaryMinus() = -Pair(incarnation.createMolecule(this), incarnation.createConcentration()) context(incarnation: Incarnation, _: Node) - operator fun Pair.unaryMinus() = -Pair(incarnation.createMolecule(first), second) + operator fun Pair.unaryMinus() = -Pair(incarnation.createMolecule(first), second) } @@ -106,15 +113,15 @@ interface TimeDistributionContext> { val timeDistribution: TimeDistribution get() = timeDistribution context(node: Node) - fun > program(reaction: R, block: context(R) ActionableContext.() -> Unit = { }) { + fun > program(reaction: R, block: context(R) ActionableContext.() -> Unit = { }) { context(reaction) { - object : ActionableContext { }.block() + ActionableContext.block() } node.addReaction(reaction) } context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node, timeDistribution: TimeDistribution) - fun program(program: String?, block: context(Reaction) ActionableContext.() -> Unit = { }) = + fun program(program: String?, block: context(Reaction) ActionableContext.() -> Unit = { }) = program( incarnation.createReaction(randomGenerator, environment, node, timeDistribution, program), block @@ -145,14 +152,14 @@ interface DeploymentContext> { ) context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program(program: String? = null, timeDistribution: Any? = null, block: context(Reaction) ActionableContext.() -> Unit = { }) = + fun program(program: String? = null, timeDistribution: Any? = null, block: context(Reaction) ActionableContext.() -> Unit = { }) = withTimeDistribution(timeDistribution) { program(program, block) } context(_: Incarnation, _: Node) - fun contents(block: context(Incarnation) ContentContext.() -> Unit) { - object : ContentContext { }.block() + fun contents(block: context(Incarnation) ContentContext.() -> Unit) { + ContentContext.block() } context(node: Node) @@ -181,11 +188,11 @@ interface DeploymentContext> { } } -interface DeploymentsContext> { - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment) - fun deploy(deployment: Deployment

, block: context(RandomGenerator, Node) DeploymentContext.() -> Unit = {}) { +object DeploymentsContext { + context(randomGenerator: RandomGenerator, environment: Environment) + fun > deploy(deployment: Deployment

, nodeFactory: (P) -> Node, block: context(RandomGenerator, Node) DeploymentContext.() -> Unit = {}) { deployment.forEach { position -> - val node: Node = incarnation.createNode(randomGenerator, environment, TODO()) + val node: Node = nodeFactory(position) context(node) { object : DeploymentContext { override val position: P get() = position @@ -193,24 +200,45 @@ interface DeploymentsContext> { } environment.addNode(node, position) } + } + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment) + fun > deploy(deployment: Deployment

, nodeParameter: String? = null, block: context(RandomGenerator, Node) DeploymentContext.() -> Unit = {}) = + deploy(deployment, { incarnation.createNode(randomGenerator, environment, nodeParameter) }, block) } -interface TerminatorsContext> { - operator fun TerminationPredicate.unaryMinus() +object TerminatorsContext { + context(environment: Environment) + operator fun > TerminationPredicate.unaryMinus() = environment.addTerminator(this) } interface EnvironmentContext> { - fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) - fun globalProgram(timeDistribution: TimeDistribution, globalReaction: GlobalReaction, block: context(GlobalReaction) ActionableContext.() -> Unit = {}) - fun layer(molecule: Molecule, layer: Layer) + fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) + + context(environment: Environment) + fun globalProgram(timeDistribution: TimeDistribution, globalReaction: GlobalReaction, block: context(GlobalReaction) ActionableContext.() -> Unit = {}) { + context(globalReaction) { + ActionableContext.block() + } + environment.addGlobalReaction(globalReaction) + } - context(incarnation: Incarnation) + context(environment: Environment) + fun layer(molecule: Molecule, layer: Layer) = environment.addLayer(molecule, layer) + + context(incarnation: Incarnation, environment: Environment) fun layer(molecule: String? = null, layer: Layer) = layer(incarnation.createMolecule(molecule), layer) - fun monitor(monitor: OutputMonitor) - fun networkModel(model: LinkingRule) - fun terminator(terminator: TerminationPredicate) + + context(environment: Environment) + fun networkModel(model: LinkingRule) = when(val currentRule = environment.linkingRule) { + is NoLinks -> environment.linkingRule = model + is CombinedLinkingRule -> environment.linkingRule = CombinedLinkingRule(currentRule.subRules + model) + else -> environment.linkingRule = CombinedLinkingRule(listOf(environment.linkingRule, model)) + } + + context(environment: Environment) + fun terminator(terminator: TerminationPredicate) = environment.addTerminator(terminator) } interface ExporterContext> { @@ -228,9 +256,11 @@ interface SimulationContext> { fun > environment(environment: E, block: context(E) EnvironmentContext.() -> Unit) fun exportWith(exporter: Exporter, block: ExporterContext.() -> Unit) fun scenarioRandomGenerator(randomGenerator: RandomGenerator) - fun scenarioSeed(seed: Long) + fun scenarioSeed(seed: Long) = scenarioRandomGenerator(MersenneTwister(seed)) fun simulationRandomGenerator(randomGenerator: RandomGenerator) - fun simulationSeed(seed: Long) + fun simulationSeed(seed: Long) = simulationRandomGenerator(MersenneTwister(seed)) + fun monitor(monitor: OutputMonitor) + fun launcher(launcher: Launcher) fun variable(variable: Variable): VariableProvider } @@ -241,13 +271,85 @@ context(_: Incarnation) fun SimulationContext.environment(block: context(Continuous2DEnvironment) EnvironmentContext.() -> Unit) = environment(continuous2DEnvironment(), block) -fun , I : Incarnation> simulation(incarnation: I, block: context(I) SimulationContext.() -> Unit): Unit = TODO() +fun , I : Incarnation> simulation(incarnation: I, block: context(I) SimulationContext.() -> Unit): Loader = object : Loader { + + override var constants: Map = emptyMap() + override val remoteDependencies: List get() = TODO("Not yet implemented") + override var launcher: Launcher = DefaultLauncher() + override val dependentVariables: Map> = emptyMap() + override var variables: Map> = emptyMap() + + @Suppress("UNCHECKED_CAST") + override fun > getWith(values: Map): Simulation = getWithTyped(values) as Simulation + + private fun getWithTyped(values: Map): Simulation { + var theEnvironment: Environment? = null + var simulationRandomGenerator: RandomGenerator = MersenneTwister(0) + var scenarioRandomGenerator: RandomGenerator = MersenneTwister(0) + context(incarnation) { + object : SimulationContext { + override fun > environment( + environment: E, + block: context(E) EnvironmentContext.() -> Unit + ) { + context(environment) { + object : EnvironmentContext { + override fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) { + TODO("Not yet implemented") + } + }.block() + } + theEnvironment = environment + } -fun > simulationOnMap(incarnation: I, block: context(I) SimulationContext.() -> Unit): Unit = simulation(incarnation, block) + override fun exportWith( + exporter: Exporter, + block: ExporterContext.() -> Unit + ) { + TODO("Not yet implemented") + } + + override fun scenarioRandomGenerator(randomGenerator: RandomGenerator) { + checkSeedCanBeSet() + scenarioRandomGenerator = randomGenerator + } + + override fun simulationRandomGenerator(randomGenerator: RandomGenerator) { + checkSeedCanBeSet() + simulationRandomGenerator = randomGenerator + } + + override fun monitor(monitor: OutputMonitor) { + TODO("Not yet implemented") + } + + override fun launcher(launcher: Launcher) { + TODO("Not yet implemented") + } + + override fun variable(variable: Variable): VariableProvider { + TODO("Not yet implemented") + } + + fun checkSeedCanBeSet() { + check(theEnvironment == null) { + "Seeds must be set before the environment is defined, otherwise it might be used to create random elements in the environment with an unexpected seed" + } + } + }.block() + } + TODO() + } +} + +fun > simulationOnMap(incarnation: I, block: context(I) SimulationContext.() -> Unit) = simulation(incarnation, block) fun > simulation2D(incarnation: I, block: context(I) SimulationContext.() -> Unit) = simulation(incarnation, block) fun main() { + simulation(ProtelisIncarnation()) { + + } simulation2D(SAPEREIncarnation()) { val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) @@ -314,9 +416,7 @@ fun main() { } } simulation2D(SAPEREIncarnation()) { - environment { - monitor(SimpleMonitor()) - } + monitor(SimpleMonitor()) } simulationOnMap(SAPEREIncarnation()){ environment(oSMEnvironment( "vcm.pbf", false)) { From cd542c505e2de909b7a008568b0bdbce5f5704e0 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 9 Feb 2026 19:59:54 +0100 Subject: [PATCH 161/196] The new DSL seems to work --- .../model/environments/AbstractEnvironment.kt | 2 +- .../model/terminators/StableForSteps.kt | 8 +- .../unibo/alchemist/boundary/dsl/DSLLoader.kt | 77 --- .../it/unibo/alchemist/boundary/dsl/Dsl.kt | 90 --- .../boundary/dsl/aliases/Extractors.kt | 17 - .../boundary/dsl/model/ContentContext.kt | 53 -- .../boundary/dsl/model/DeploymentContext.kt | 110 ---- .../boundary/dsl/model/DeploymentsContext.kt | 82 --- .../dsl/model/DeploymentsContextImpl.kt | 175 ----- .../boundary/dsl/model/ExporterContext.kt | 67 -- .../boundary/dsl/model/ExporterContextImpl.kt | 33 - .../dsl/model/GlobalProgramsContext.kt | 45 -- .../boundary/dsl/model/LayerContext.kt | 51 -- .../boundary/dsl/model/LayerContextImpl.kt | 25 - .../dsl/model/OutputMonitorsContext.kt | 46 -- .../boundary/dsl/model/ProgramContext.kt | 145 ----- .../boundary/dsl/model/ProgramsContext.kt | 81 --- .../boundary/dsl/model/ProgramsContextImpl.kt | 168 ----- .../boundary/dsl/model/PropertiesContext.kt | 79 --- .../dsl/model/PropertiesContextImpl.kt | 93 --- .../dsl/model/RandomGeneratorProvider.kt | 20 - .../boundary/dsl/model/SeedsContext.kt | 46 -- .../boundary/dsl/model/SimulationContext.kt | 217 ------- .../dsl/model/SimulationContextImpl.kt | 210 ------ .../boundary/dsl/model/TerminatorsContext.kt | 47 -- .../boundary/dsl/model/VariablesContext.kt | 154 ----- .../boundary/dsl/util/LoadingSystemLogger.kt | 18 - .../boundary/kotlindsl/ActionableContext.kt | 39 ++ .../boundary/kotlindsl/AlchemistKotlinDSL.kt | 221 +++++++ .../AlchemistScript.kt | 6 +- .../boundary/kotlindsl/ContentContext.kt | 84 +++ .../boundary/kotlindsl/DeploymentContext.kt | 188 ++++++ .../boundary/kotlindsl/DeploymentsContext.kt | 71 ++ .../boundary/kotlindsl/EnvironmentContext.kt | 132 ++++ .../boundary/kotlindsl/ExporterContext.kt | 37 ++ .../boundary/kotlindsl/SimulationContext.kt | 128 ++++ .../boundary/kotlindsl/TerminatorsContext.kt | 37 ++ .../kotlindsl/TimeDistributionContext.kt | 93 +++ .../boundary/kotlindsl/VariableProvider.kt | 41 ++ .../modelproviders/KotlinDslProvider.kt | 2 +- alchemist-loading/src/test/kotlin/DSL2.kt | 614 ------------------ .../unibo/alchemist/dsl/DslLoaderFunctions.kt | 460 ------------- .../alchemist/dsl/RuntimeComparisonHelper.kt | 9 +- .../alchemist/dsl/SimulationsComparisons.kt | 193 +++--- .../it/unibo/alchemist/dsl/TestComparators.kt | 6 +- .../it/unibo/alchemist/dsl/TestContents.kt | 18 +- .../it/unibo/alchemist/dsl/TestDSLLoading.kt | 318 +++++++++ .../it/unibo/alchemist/dsl/TestDeployments.kt | 29 +- .../it/unibo/alchemist/dsl/TestSimulations.kt | 11 +- .../it/unibo/alchemist/dsl/TestVariables.kt | 60 +- .../model/physics/reactions/PhysicsUpdate.kt | 8 +- 51 files changed, 1571 insertions(+), 3393 deletions(-) delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/aliases/Extractors.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContextImpl.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/RandomGeneratorProvider.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SeedsContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/TerminatorsContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ActionableContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt rename alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/{dsl/scripting => kotlindsl}/AlchemistScript.kt (95%) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ContentContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentsContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/EnvironmentContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ExporterContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TimeDistributionContext.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableProvider.kt delete mode 100644 alchemist-loading/src/test/kotlin/DSL2.kt delete mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt create mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDSLLoading.kt diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt index a17fedfde4..7d413193e5 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt @@ -57,7 +57,7 @@ abstract class AbstractEnvironment> protected constructor( private val _layers: MutableMap> = LinkedHashMap() private val neighCache = TIntObjectHashMap>() private val nodeToPos = TIntObjectHashMap

() - private val spatialIndex: SpatialIndex> = requireNotNull(internalIndex) + private val spatialIndex: SpatialIndex> = internalIndex override val layers: ListSet> get() = ArrayListSet(_layers.values) diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/terminators/StableForSteps.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/terminators/StableForSteps.kt index 8b4696ac5a..642aafd9eb 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/terminators/StableForSteps.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/terminators/StableForSteps.kt @@ -43,7 +43,7 @@ import java.util.function.Predicate * @param equalIntervals The amount of [checkInterval] intervals that need to pass * (during which the environment doesn't change) for [test] to return true */ -data class StableForSteps>(private val checkInterval: Long, private val equalIntervals: Long) : +data class StableForSteps>(private val checkInterval: Long, private val equalIntervals: Long) : TerminationPredicate { private var success: Long = 0 private var positions: Map, P> = emptyMap() @@ -72,8 +72,10 @@ data class StableForSteps>(private val checkInterval: Long, pr } private companion object { - private fun makeTable(size: Int): Table, Molecule, T> = - Tables.newCustomTable(Maps.newLinkedHashMapWithExpectedSize, Map>(size)) { + private fun makeTable(size: Int): Table, Molecule, T> = + Tables.newCustomTable, Molecule, T>( + Maps.newLinkedHashMapWithExpectedSize, Map>(size), + ) { Maps.newLinkedHashMapWithExpectedSize(size) } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt deleted file mode 100644 index 4c5c2395a5..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/DSLLoader.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl - -import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.dsl.model.SimulationContext -import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl -import it.unibo.alchemist.boundary.exporters.GlobalExporter -import it.unibo.alchemist.core.Engine -import it.unibo.alchemist.core.Simulation -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Position -import java.util.concurrent.Semaphore - -/** - * Abstract base class for single-use DSL loaders. - * - * @param ctx The simulation context. - */ -abstract class DSLLoader(private val ctx: SimulationContext<*, *>) : Loader { - - @Suppress("UNCHECKED_CAST") - override fun > getWith(values: Map): Simulation = - SingleUseLoader(ctx as SimulationContext).load(values) - - private inner class SingleUseLoader>(private val ctx: SimulationContext) { - private val mutex = Semaphore(1) - private var consumed = false - - fun load(values: Map): Simulation { - try { - mutex.acquireUninterruptibly() - check(!consumed) { "This loader has already been consumed! This is a bug in Alchemist" } - consumed = true - } finally { - mutex.release() - } - val typedCtx = ctx as SimulationContextImpl - val unknownVariableNames = values.keys - this@DSLLoader.variables.keys - require(unknownVariableNames.isEmpty()) { - "Unknown variables provided: $unknownVariableNames." + - " Valid names: ${this@DSLLoader.variables.keys}. Provided: ${values.keys}" - } - // VARIABLE REIFICATION - ctx.variablesContext.addReferences( - ctx.variablesContext.dependentVariables.map { (k, v) -> - k to v() - }.toMap(), - ) - val simulationIstance = typedCtx.build(values) - val environment = simulationIstance.environment - val engine = Engine(environment) - // MONITORS - simulationIstance.monitors.forEach { monitor -> - engine.addOutputMonitor(monitor) - } - // EXPORTERS - val exporters = simulationIstance.exporters.map { - it.type.apply { - bindDataExtractors(it.extractors) - } - } - exporters.forEach { it.bindVariables(ctx.variablesContext.references.get()) } - if (exporters.isNotEmpty()) { - engine.addOutputMonitor(GlobalExporter(exporters)) - } - return engine - } - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt deleted file mode 100644 index 3eb82ced93..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/Dsl.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl - -import it.unibo.alchemist.boundary.DependentVariable -import it.unibo.alchemist.boundary.Launcher -import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.model.SimulationContext -import it.unibo.alchemist.boundary.dsl.model.SimulationContextImpl -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.environments.Continuous2DEnvironment -import it.unibo.alchemist.model.environments.Euclidean2DEnvironment -import it.unibo.alchemist.model.positions.Euclidean2DPosition -import org.apache.commons.math3.random.RandomGenerator - -/** - * Marker annotation for Alchemist DSL elements. - * - * This annotation is used to mark DSL context classes and functions, - * preventing scope pollution in DSL blocks. - */ -@DslMarker -annotation class AlchemistDsl - -/** - * Main DSL object for creating Alchemist simulations. - * - * This object provides factory methods for creating simulation loaders - * and configuring Alchemist simulations using a type-safe DSL. - */ -object Dsl { - /** - * Creates a loader from a simulation context. - * - * @param dsl The simulation context. - * @return A loader instance. - */ - private fun , E : Environment> createLoader(builder: SimulationContext): Loader = - object : DSLLoader(builder) { - override val constants: Map = emptyMap() - override val dependentVariables: Map> = emptyMap() - override val variables: Map> = builder.variablesContext.variables - override val remoteDependencies: List = emptyList() - override val launcher: Launcher = builder.launcher - } - - /** - * Creates a simulation with a custom environment. - * - * @param incarnation The incarnation instance. - * @param block The simulation configuration block. - * @return A loader instance. - */ - fun , E : Environment> simulation( - incarnation: Incarnation, - block: context( - Incarnation, - RandomGenerator, - ) SimulationContext.() -> Unit, - ): Loader { - val ctx = SimulationContextImpl(incarnation) - ctx.apply { - context(incarnation, ctx.scenarioGenerator) { - block() - } - } - return createLoader(ctx) - } - - /** - * Creates a 2D simulation with a Euclidean2DEnvironment. - */ - fun simulation2D( - incarnation: Incarnation, - block: context( - Incarnation, - RandomGenerator, - ) SimulationContext>.() -> Unit, - ): Loader = simulation>(incarnation, block) -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/aliases/Extractors.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/aliases/Extractors.kt deleted file mode 100644 index 85b7a0418d..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/aliases/Extractors.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.aliases - -import it.unibo.alchemist.boundary.extractors.Time - -/** - * Helper to disambiguate Time() in scripts: resolves to the extractor, not the model type. - */ -fun Time(precision: Int? = null): Time = Time(precision) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt deleted file mode 100644 index c7e31af28f..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ContentContext.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.PositionBasedFilter - -/** - * Context interface for configuring node content (molecules and concentrations). - * - * This context is used within [DeploymentContext] blocks to define the initial - * content of nodes deployed at specific positions. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [it.unibo.alchemist.model.Position]. - * - * @see [DeploymentContext] for the parent context - * @see [it.unibo.alchemist.model.Incarnation.createMolecule] - * @see [it.unibo.alchemist.model.Incarnation.createConcentration] - */ -interface ContentContext> { - /** - * The optional position filter applied to this content context. - * - * If set, content is only applied to nodes at positions matching this filter. - */ - val filter: PositionBasedFilter

? - - /** - * The molecule name to inject into nodes. - * - * The molecule is created using the incarnation's molecule factory. - * - * @see [it.unibo.alchemist.model.Incarnation.createMolecule] - */ - var molecule: String? - - /** - * The concentration value for the molecule. - * - * The concentration is created using the incarnation's concentration factory. - * - * @see [it.unibo.alchemist.model.Incarnation.createConcentration] - */ - var concentration: T? -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt deleted file mode 100644 index f72f54de3a..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentContext.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.PositionBasedFilter - -/** - * Context interface for configuring a single deployment. - * - * This context allows configuring content (molecules and concentrations), programs (reactions), - * properties, and custom node factories for nodes deployed at positions defined by the deployment. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - * - * @see [DeploymentsContext] for the parent context - * @see [ContentContext] for configuring node content - * @see [ProgramsContext] for configuring node programs - * @see [PropertiesContext] for configuring node properties - */ -// TODO: remove when detekt false positive is fixed -@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -interface DeploymentContext> { - /** - * The deployments context this deployment context belongs to. - */ - val ctx: DeploymentsContext - - /** - * Configures content (molecules and concentrations) for all positions in the deployment. - * - * All nodes deployed at positions defined by this deployment will receive the configured content. - * - * ```kotlin - * all { - * molecule = "token" - * concentration = 1.0 - * } - * ``` - * - * @param block The content configuration block. - * @see [ContentContext] - */ - context(_: Node) - fun all(block: ContentContext.() -> Unit) - - /** - * Configures content for positions inside a filter. - * - * Only nodes deployed at positions matching the filter will receive the configured content. - * - * ```kotlin - * inside(RectangleFilter(-1.0, -1.0, 2.0, 2.0)) { - * molecule = "specialToken" - * } - * ``` - * - * @param filter The position filter to apply. - * @param block The content configuration block. - * @see [PositionBasedFilter] - * @see [ContentContext] - */ - context(_: Node) - fun inside(filter: PositionBasedFilter<*>, block: context(Node) ContentContext.() -> Unit) - - /** - * Configures programs (reactions) for this deployment. - * - * Programs define the behavior of nodes through reactions. - * - * ```kotlin - * programs { - * all { - * program = "{token} --> {firing}" - * } - * } - * ``` - * - * @param block The programs configuration block. - * @see [ProgramsContext] - */ - fun programs(block: ProgramsContext.() -> Unit) - - /** - * Configures properties for this deployment. - * - * Properties can be assigned to nodes based on their position. - * - * ```kotlin - * properties { - * inside(RectangleFilter(-3.0, -3.0, 2.0, 2.0)) { - * add(MyNodeProperty()) - * } - * } - * ``` - * - * @param block The properties configuration block. - * @see [PropertiesContext] - */ - fun properties(block: PropertiesContext.() -> Unit) -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt deleted file mode 100644 index 41003e3d71..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContext.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.model.Deployment -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.Position -import org.apache.commons.math3.random.RandomGenerator - -/** - * Context interface for managing node deployments in a simulation. - * - * Deployments define where nodes are placed in the environment and can be configured - * with content (molecules and concentrations), programs (reactions), and properties. - * - * ## Usage Example - * - * ```kotlin - * simulation(incarnation) { - * deployments { - * deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.25)) { - * all { - * molecule = "token" - * concentration = 1.0 - * } - * programs { - * all { - * program = "{token} --> {firing}" - * } - * } - * } - * } - * } - * ``` - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [it.unibo.alchemist.model.Position]. - * - * @see [SimulationContext.deployments] for configuring deployments in a simulation - * @see [it.unibo.alchemist.model.Deployment] for the deployment interface - * @see [DeploymentContext] for configuring individual deployments - */ -@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -interface DeploymentsContext> { - /** - * Deploys nodes using a deployment with a configuration block. - * - * The configuration block allows setting content, programs, properties, and custom node factories. - * - * ```kotlin - * deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.25)) { - * all { molecule = "token" } - * } - * ``` - * - * @param deployment The deployment that defines node positions. - * @param block The configuration block for the deployment. - * @see [it.unibo.alchemist.model.Deployment] - */ - // TODO: fix the doc - context(_: Incarnation, environment: Environment) - fun deploy( - deployment: Deployment

, - nodeFactory: context(RandomGenerator, Environment) () -> Node = { - contextOf>().incarnation.createNode( - contextOf(), - contextOf>(), - null, - ) - }, - block: context(Environment, Node) DeploymentContext.() -> Unit = { }, - ) -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt deleted file mode 100644 index 26029c15cc..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/DeploymentsContextImpl.kt +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger -import it.unibo.alchemist.model.Actionable -import it.unibo.alchemist.model.Deployment -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.PositionBasedFilter -import it.unibo.alchemist.model.linkingrules.CombinedLinkingRule -import it.unibo.alchemist.model.linkingrules.NoLinks -import org.apache.commons.math3.random.RandomGenerator - -/** - * Context for managing deployments in a simulation. - * - * @param T The type of molecule concentration. - * @param P The type of position. - * @param ctx The simulation context. - */ -open class DeploymentsContextImpl>(private val simulationRandomGenerator: RandomGenerator) : - DeploymentsContext { - - context(_: Incarnation, environment: Environment) - override fun deploy( - deployment: Deployment

, - nodeFactory: context(RandomGenerator, Environment) () -> Node, - block: context(Environment, Node) DeploymentContext.() -> Unit, - ) { - context(simulationRandomGenerator) { - logger.debug("Deploying deployment: {}", deployment) - // Additional linking rules - deployment.getAssociatedLinkingRule()?.let { newLinkingRule -> - val composedLinkingRule = - when (val linkingRule = environment.linkingRule) { - is NoLinks -> newLinkingRule - is CombinedLinkingRule -> CombinedLinkingRule(linkingRule.subRules + listOf(newLinkingRule)) - else -> CombinedLinkingRule(listOf(linkingRule, newLinkingRule)) - } - environment.linkingRule = composedLinkingRule - } - deployment.forEach { position -> - logger.debug("visiting position: {} for deployment: {}", position, deployment) - logger.debug("creaing node for deployment: {}", deployment) - val node = nodeFactory() - context(node) { - // load properties - val deploymentContext = DeploymentContextImpl(deployment).apply { block() } - deploymentContext.propertiesContext.applyToNode(node, position) - // load contents - val contents = deploymentContext.contents - for (content in contents) { - deploymentContext.applyToNodes(node, position, content) - } - // load programs - val programs = deploymentContext.programsContext.programs - val createdPrograms = mutableListOf?, Actionable>>() - for (programEntry in programs) { - val pp = deploymentContext.programsContext.applyToNodes( - node, - position, - programEntry.program, - programEntry.filter, - ) - createdPrograms.add(pp) - } - logger.debug("programs={}", createdPrograms) - logger.debug("Adding node to environment at position: {}", position) - } - environment.addNode(node, position) - } - } - } - - /** - * Context for configuring a single deployment. - * - * @param deployment The deployment being configured. - */ - inner class DeploymentContextImpl(val deployment: Deployment

) : DeploymentContext { - override val ctx: DeploymentsContext = this@DeploymentsContextImpl - - /** - * The list of content contexts for this deployment. - */ - val contents: MutableList = mutableListOf() - - /** - * The properties context for this deployment. - */ - var propertiesContext: PropertiesContextImpl = PropertiesContextImpl(this@DeploymentContextImpl) - - /** - * The programs context for this deployment. - */ - val programsContext: ProgramsContextImpl = ProgramsContextImpl(this@DeploymentContextImpl) - init { - logger.debug("Visiting deployment: {}", deployment) - } - - context(_: Node) - override fun all(block: ContentContext.() -> Unit) { - logger.debug("Adding content for all positions") - val c = ContentContextImpl().apply(block) - contents.add(c) - } - - context(_: Node) - override fun inside(filter: PositionBasedFilter<*>, block: context(Node) ContentContext.() -> Unit) { - @Suppress("UNCHECKED_CAST") - val typedFilter = filter as PositionBasedFilter

- logger.debug("Adding content for positions inside filter: {}", typedFilter) - val c = ContentContextImpl(typedFilter).apply { block() } - contents.add(c) - } - - override fun programs(block: ProgramsContext.() -> Unit) { - programsContext.apply(block) - } - - override fun properties(block: PropertiesContext.() -> Unit) { - propertiesContext.apply(block) - } - - /** - * Applies content to nodes at a specific position. - * - * @param node The node to apply content to. - * @param position The position of the node. - * @param content The content context to apply. - */ - context(incarnation: Incarnation) - internal fun applyToNodes(node: Node, position: P, content: ContentContextImpl) { - logger.debug("Applying node to nodes for position: {}, deployment {}", position, deployment) - if (content.filter == null || content.filter.contains(position)) { - logger.debug("Creating molecule for node at position: {}", position) - val mol = incarnation.createMolecule( - content.molecule - ?: error("Molecule not specified"), - ) - logger.debug("Creating concentration for molecule: {}", mol) - val conc = incarnation.createConcentration(content.concentration) - logger.debug("Setting concentration for molecule: {} to node at position: {}", mol, position) - node.setConcentration(mol, conc) - } - } - - /** - * Context for configuring content (molecules and concentrations) for nodes. - * - * @param filter Optional position filter for applying content. - */ - inner class ContentContextImpl(override val filter: PositionBasedFilter

? = null) : ContentContext { - /** - * The molecule name. - */ - override var molecule: String? = null - - /** - * The concentration value. - */ - override var concentration: T? = null - } - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt deleted file mode 100644 index 11c8e1a1d4..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContext.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.Exporter -import it.unibo.alchemist.boundary.Extractor -import it.unibo.alchemist.boundary.dsl.AlchemistDsl -import it.unibo.alchemist.model.Position - -/** - * Context interface for configuring data exporters in a simulation. - * - * Exporters define how simulation data is extracted and exported, supporting formats - * such as CSV, MongoDB, and custom formats. - * Data can be exported per-node or aggregated - * using statistical functions. - * - * ## Usage Example - * - * ```kotlin -* exporter { -* type = CSVExporter("output", 4.0) -* data(Time(), moleculeReader("moleculeName")) -* } - * ``` - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - * - * @see [SimulationContext.exporter] for adding exporters to a simulation - * @see [Exporter] for the exporter interface - * @see [Extractor] for data extraction - */ -@AlchemistDsl -interface ExporterContext> { - - /** The parent simulation context. */ - val ctx: SimulationContext - - /** - * The exporter instance that handles data output. - * - * @see [Exporter] - */ - var type: Exporter - - /** - * Sets the data extractors for this exporter. - * - * Extractors define which data should be exported from the simulation. - * - * ```kotlin - * data(Time(), moleculeReader("moleculeName")) - * ``` - * - * @param extractors The extractors to use for data extraction. - * @see [Extractor] - */ - fun data(vararg extractors: Extractor<*>) -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt deleted file mode 100644 index 075d3bd37f..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ExporterContextImpl.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.Exporter -import it.unibo.alchemist.boundary.Extractor -import it.unibo.alchemist.model.Position - -/** - * Context for configuring exporters in a simulation. - * - * @param T The type of molecule concentration. - * @param P The type of position. - */ -class ExporterContextImpl>(override val ctx: SimulationContext) : ExporterContext { - override lateinit var type: Exporter - - /** - * The list of data extractors. - */ - var extractors: List> = emptyList() - - override fun data(vararg extractors: Extractor<*>) { - this.extractors = extractors.toList() - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt deleted file mode 100644 index c979c15ebc..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/GlobalProgramsContext.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.model.GlobalReaction -import it.unibo.alchemist.model.Position - -/** - * Context for configuring global reactions in a simulation. - * - * @param T The type of molecule concentration. - * @param P The type of position. - */ -@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -interface GlobalProgramsContext> { - /** The parent simulation context. */ - val ctx: SimulationContext - - /** - * Adds a global reaction to the simulation. - * - * @param this The global reaction to add. - */ - operator fun GlobalReaction.unaryPlus() -} - -/** - * Implementation of [GlobalProgramsContext]. - * - * @param T The type of molecule concentration. - * @param P The type of position. - */ -class GlobalProgramsContextImpl>(override val ctx: SimulationContext) : - GlobalProgramsContext { - override fun GlobalReaction.unaryPlus() { - ctx.environment.addGlobalReaction(this) - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt deleted file mode 100644 index 67f9f4b116..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContext.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.dsl.AlchemistDsl -import it.unibo.alchemist.model.Layer -import it.unibo.alchemist.model.Position - -/** - * Context interface for configuring spatial layers in a simulation. - * - * Layers define overlays of data that can be sensed everywhere in the environment. - * They can be used to model physical properties such as pollution, light, temperature, etc. - * - * ## Usage Example - * - * ```kotlin -* layer { -* molecule = "A" -* layer = StepLayer(2.0, 2.0, 100.0, 0.0) -* } - * ``` - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - * - * @see [SimulationContext.layer] for adding layers to a simulation - * @see [Layer] for the layer interface - */ -@AlchemistDsl -interface LayerContext> { - /** - * The molecule name associated with this layer. - * - */ - var molecule: String? - - /** - * The layer instance that provides spatial data. - * - * @see [Layer] - */ - var layer: Layer? -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContextImpl.kt deleted file mode 100644 index 89d546c573..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/LayerContextImpl.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.model.Layer -import it.unibo.alchemist.model.Position - -/** - * Context for configuring layers in a simulation. - * - * @param T The type of molecule concentration. - * @param P The type of position. - */ -class LayerContextImpl> : LayerContext { - override var molecule: String? = null - - override var layer: Layer? = null -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt deleted file mode 100644 index 9e485d62f3..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/OutputMonitorsContext.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.OutputMonitor -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Position - -/** - * Context for configuring output monitors in a simulation. - * - * @param T The type of molecule concentration. - * @param P The type of position. - */ -interface OutputMonitorsContext, E : Environment> { - /** The parent simulation context. */ - val ctx: SimulationContext - - /** - * Adds an output monitor to the simulation. - * - * @param this The output monitor to add. - */ - operator fun OutputMonitor.unaryPlus() -} - -/** - * Implementation of [OutputMonitorsContext]. - * - * @param T The type of molecule concentration. - * @param P The type of position. - */ -class OutputMonitorsContextImpl, E : Environment>( - override val ctx: SimulationContextImpl, -) : OutputMonitorsContext { - override fun OutputMonitor.unaryPlus() { - ctx.monitors += this - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt deleted file mode 100644 index 314bd25cb9..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramContext.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.dsl.AlchemistDsl -import it.unibo.alchemist.model.Action -import it.unibo.alchemist.model.Actionable -import it.unibo.alchemist.model.Condition -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.Reaction -import it.unibo.alchemist.model.TimeDistribution -import org.apache.commons.math3.random.RandomGenerator - -/** - * Context interface for configuring a single program (reaction) for a node. - * - * This context is used within [ProgramsContext] blocks to define reactions with - * their time distributions, conditions, and actions. - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [it.unibo.alchemist.model.Position]. - * - * @see [ProgramsContext] for the parent context - * @see [it.unibo.alchemist.model.Reaction] for the reaction interface - * @see [it.unibo.alchemist.model.TimeDistribution] for time distribution - * @see [it.unibo.alchemist.model.Action] for reaction actions - * @see [it.unibo.alchemist.model.Condition] for reaction conditions - */ -// TODO: remove when detekt false positive is fixed -@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -@AlchemistDsl -interface ProgramContext> { - /** - * The programs context this program context belongs to. - */ - val ctx: ProgramsContext - - /** - * The node this program context is configuring. - */ - val node: Node - - /** - * The program specification as a string. - * - * The format depends on the incarnation being used. - */ - var program: String? - - /** - * The time distribution for the reaction. - * - * @see [it.unibo.alchemist.model.TimeDistribution] - */ - var timeDistribution: TimeDistribution? - - /** - * An optional custom reaction instance. - * - * If provided, this reaction will be used instead of creating one from [program]. - * - * @see [it.unibo.alchemist.model.Reaction] - */ - var reaction: Reaction? - - /** - * Sets the time distribution using a string specification. - * - * The string is processed by the incarnation to create a [TimeDistribution]. - * - * ```kotlin - * timeDistribution("1") - * ``` - * - * @param td The time distribution specification string. - * @see [TimeDistribution] - * @see [it.unibo.alchemist.model.Incarnation.createTimeDistribution] - */ - context(_: Incarnation, _: RandomGenerator, _: Environment, _: Node) - fun timeDistribution(td: String) - - /** - * Adds an action to the program. - * - * Actions are executed when the reaction fires and all conditions are met. - * - * @param block A factory function that creates the action. - * @see [it.unibo.alchemist.model.Action] - */ - fun addAction(block: () -> Action) - - /** - * Adds an action to the program using the incarnation createAction function. - * - * @param action the action - * @see [it.unibo.alchemist.model.Incarnation.createAction] - */ - context(_: Incarnation, _: RandomGenerator, _: Environment, _: Node, _: Actionable) - fun addAction(action: String) = addAction { - contextOf>().createAction( - contextOf(), - contextOf>(), - contextOf>(), - contextOf>(), - action, - ) - } - - /** - * Adds a condition to the program. - * - * Conditions must all be satisfied for the reaction to fire. - * - * @param block A factory function that creates the condition. - * @see [it.unibo.alchemist.model.Condition] - */ - fun addCondition(block: () -> Condition) - - /** - * Adds a condition to the program, using the incarnation createCondition function. - * - * @param condition the condition - * @see [Incarnation.createCondition] - */ - context(_: Incarnation, _: RandomGenerator, _: Environment, _: Node, _: Actionable) - fun addCondition(condition: String) = addCondition { - contextOf>().createCondition( - contextOf(), - contextOf>(), - contextOf>(), - contextOf>(), - condition, - ) - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt deleted file mode 100644 index daadf520e5..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContext.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.dsl.AlchemistDsl -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.PositionBasedFilter -import it.unibo.alchemist.model.Reaction -import it.unibo.alchemist.model.TimeDistribution - -/** - * Context interface for configuring programs (reactions) in a deployment. - * - * Programs define the behavior of nodes through reactions that execute actions - * when conditions are met. Programs can be applied to all nodes or filtered by position. - * - * ## Usage Example - * - * ```kotlin - * deployments { - * deploy(deployment) { - * programs { - * all { - * timeDistribution("1") - * program = "{token} --> {firing}" - * } - * inside(RectangleFilter(-1.0, -1.0, 2.0, 2.0)) { - * program = "{firing} --> +{token}" - * } - * } - * } - * } - * ``` - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - * - * @see [DeploymentContext.programs] for configuring programs in a deployment - * @see [Reaction] for the reaction interface - * @see [TimeDistribution] for time distribution configuration - */ -@AlchemistDsl -// TODO: remove when detekt false positive is fixed -@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -interface ProgramsContext> { - /** - * The deployment context this programs context belongs to. - */ - val ctx: DeploymentContext - - /** - * Configures a program for all nodes in the deployment. - * - * @param block The program configuration block. - */ - context(_: Environment, _: Node) - fun all(block: context(Environment, Node) ProgramContext.() -> Unit) - - /** - * Configures a program for nodes inside a position filter. - * - * Only nodes whose positions match the filter will receive the configured program. - * - * @param filter The position filter to apply. - * @param block The program configuration block. - * @see [PositionBasedFilter] - */ - fun inside( - filter: PositionBasedFilter

, - block: context(Environment, Node) ProgramContext.() -> Unit, - ) -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt deleted file mode 100644 index 889dad7eea..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/ProgramsContextImpl.kt +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger -import it.unibo.alchemist.model.Action -import it.unibo.alchemist.model.Actionable -import it.unibo.alchemist.model.Condition -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.PositionBasedFilter -import it.unibo.alchemist.model.Reaction -import it.unibo.alchemist.model.TimeDistribution -import org.apache.commons.math3.random.RandomGenerator - -/** - * Context for managing programs (reactions) in a simulation. - * - * @param T The type of molecule concentration. - * @param P The type of position. - * @param ctx The deployments context. - */ -// TODO: remove when detekt false positive is fixed -@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -class ProgramsContextImpl>(override val ctx: DeploymentContext) : ProgramsContext { - /** - * Entry representing a program with its filter. - * - * @param filter Optional position filter. - * @param program The program configuration block. - */ - inner class ProgramEntry( - val filter: PositionBasedFilter

?, - val program: context(Environment, Node) ProgramsContextImpl.ProgramContextImpl.() -> Unit, - ) - - /** - * List of program entries. - */ - val programs: MutableList = mutableListOf() - - context(_: Environment, _: Node) - override fun all(block: context(Environment, Node) ProgramContext.() -> Unit) { - logger.debug("Adding program for all nodes") - programs.add(ProgramEntry(null, block)) - } - - override fun inside( - filter: PositionBasedFilter

, - block: context(Environment, Node) ProgramContext.() -> Unit, - ) { - logger.debug("Adding program for nodes inside filter: {}", filter) - programs.add(ProgramEntry(filter, block)) - } - - /** - * Applies a program to nodes at a specific position. - * - * @param node The node to apply the program to. - * @param position The position of the node. - * @param program The program configuration block. - * @param filter Optional position filter. - */ - context(incarnation: Incarnation, simulationRandomGenerator: RandomGenerator, environment: Environment) - fun applyToNodes( - node: Node, - position: P, - program: context(Environment, Node) ProgramContextImpl.() -> Unit, - filter: PositionBasedFilter

?, - ): Pair?, Actionable> { - logger.debug("Applying program to node at position: {}", position) - val c = ProgramContextImpl(node).apply { - context(node) { - program() - } - } - logger.debug("Creating time distribution for program") - val timeDistribution = c.timeDistribution - ?: incarnation.createTimeDistribution( - simulationRandomGenerator, - environment, - node, - null, - ) - logger.debug("Creating reaction for program") - val r = c.reaction - ?: // Create a basic reaction with custom actions/conditions - incarnation.createReaction( - simulationRandomGenerator, - environment, - node, - timeDistribution, - c.program, - ) - logger.debug("Adding actions to reaction") - r.actions += c.actions.map { it() } - logger.debug("Adding conditions to reaction") - r.conditions += c.conditions.map { it() } - logger.debug("Adding reaction to node") - if (filter == null || filter.contains(position)) { - node.addReaction(r) - } - return filter to r - } - - /** - * Context for configuring a single program (reaction). - * - * @param node The node this program is associated with. - * @param ctx The programs' context. - */ - open inner class ProgramContextImpl(override val node: Node) : ProgramContext { - - override val ctx: ProgramsContext = this@ProgramsContextImpl - - /** - * The program name. - */ - override var program: String? = null - - /** - * Collection of action factories. - */ - var actions: Collection<() -> Action> = emptyList() - - /** - * Collection of condition factories. - */ - var conditions: Collection<() -> Condition> = emptyList() - - /** - * The time distribution for the reaction. - */ - override var timeDistribution: TimeDistribution? = null - - /** - * Optional custom reaction instance. - */ - override var reaction: Reaction? = null - - context(_: Incarnation, _: RandomGenerator, _: Environment, _: Node) - override fun timeDistribution(td: String) { - timeDistribution = contextOf>().createTimeDistribution( - contextOf(), - contextOf>(), - contextOf>(), - td, - ) - } - - override fun addAction(block: () -> Action) { - actions += block - } - - override fun addCondition(block: () -> Condition) { - conditions += block - } - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt deleted file mode 100644 index 3ac554109b..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContext.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.dsl.AlchemistDsl -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.NodeProperty -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.PositionBasedFilter - -/** - * Context interface for configuring node properties in a deployment. - * - * Properties can be assigned to nodes based on their position using filters, - * or applied to all nodes in the deployment. - * - * ## Usage Example - * - * ```kotlin - * deployments { - * deploy(deployment) { - * properties { - * inside(RectangleFilter(-3.0, -3.0, 2.0, 2.0)) { - * add(MyNodeProperty()) - * } - * all { - * add(CommonProperty()) - * } - * } - * } - * } - * ``` - * - * @param T The type of molecule concentration. - * @param P The type of position, must extend [Position]. - * - * @see [DeploymentContext.properties] for configuring properties in a deployment - * @see [NodeProperty] for the property interface - * @see [PositionBasedFilter] for position filtering - */ -// TODO: remove when detekt false positive is fixed -@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -@AlchemistDsl -interface PropertiesContext> { - /** - * The deployment context this properties context belongs to. - */ - val ctx: DeploymentContext - - /** - * Configures properties for nodes inside a position filter. - * - * Only nodes whose positions match the filter will receive the configured properties. - * - * @param filter The position filter to apply. - * @param block The property configuration block. - * @see [PositionBasedFilter] - */ - context(environment: Environment) - fun inside( - filter: PositionBasedFilter

, - block: context(Environment, Node) PropertyContext.() -> Unit, - ) - - /** - * Configures properties for all nodes in the deployment. - * - * @param block The property configuration block. - */ - fun all(block: context(Environment, Node) PropertyContext.() -> Unit) -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt deleted file mode 100644 index 90ae8b5e5d..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/PropertiesContextImpl.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.NodeProperty -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.PositionBasedFilter - -/** - * Context for managing node properties in a simulation. - * - * @param T The type of molecule concentration. - * @param P The type of position. - */ -// TODO: remove when detekt false positive is fixed -@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -class PropertiesContextImpl>(override val ctx: DeploymentContext) : PropertiesContext { - /** - * List of property contexts with their associated filters. - */ - val propertiesCtx: MutableList< - Pair< - context(Environment, Node) - PropertyContext.() -> Unit, - PositionBasedFilter

?, - >, - > = mutableListOf() - - context(_: Environment) - override fun inside( - filter: PositionBasedFilter

, - block: context(Environment, Node) PropertyContext.() -> Unit, - ) { - propertiesCtx.add(block to filter) - logger.debug("Adding property for nodes inside filter: {}", filter) - } - - override fun all(block: context(Environment, Node) PropertyContext.() -> Unit) { - propertiesCtx.add(block to null) - logger.debug("Adding property for all nodes") - } - - /** - * Applies configured properties to a node at a specific position. - * - * @param node The node to apply properties to. - * @param position The position of the node. - */ - context(_: Environment, _: Node) - fun applyToNode(node: Node, position: P) { - propertiesCtx.forEach { (propertyCtx, filter) -> - if (filter == null || filter.contains(position)) { - val properties = PropertyContextImpl(filter, node) - .apply { propertyCtx() } - .properties - properties.forEach { property -> - logger.debug("Applying property: {} to node: {}", property, node) - node.addProperty(property) - } - } - } - } - - /** - * Context for configuring properties for a specific node. - * - * @param filter Optional position filter. - * @param node The node to configure properties for. - */ - inner class PropertyContextImpl(override val filter: PositionBasedFilter

?, override val node: Node) : - PropertyContext { - override val ctx: PropertiesContext = this@PropertiesContextImpl - - /** - * List of properties to add to the node. - */ - val properties: MutableList> = mutableListOf() - - override operator fun NodeProperty.unaryPlus() { - properties.add(this) - } - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/RandomGeneratorProvider.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/RandomGeneratorProvider.kt deleted file mode 100644 index 1889fd7368..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/RandomGeneratorProvider.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import java.util.random.RandomGenerator - -/** - * Provides random generators for different simulation contexts. - * - * @param forScenario The random generator for the scenario context. - * @param forSimulation The random generator for the simulation context. - */ -data class RandomGeneratorProvider(val forScenario: RandomGenerator, val forSimulation: RandomGenerator) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SeedsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SeedsContext.kt deleted file mode 100644 index 14031454c7..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SeedsContext.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import org.apache.commons.math3.random.RandomGenerator - -/** - * Context for defining random seeds for simulation and scenario generation. - */ -interface SeedsContext { - - /** - * Sets the scenario's random generator to the default with the specified seed. - * - * @param seed the seed value - */ - fun scenario(seed: Long) - - /** - * Sets the scenario's random generator using the provided block. - * - * @param block a lambda that returns a RandomGenerator - */ - fun scenario(block: () -> RandomGenerator) - - /** - * Sets the simulation's random generator to the default with the specified seed. - * - * @param seed the seed value - */ - fun simulation(seed: Long) - - /** - * Sets the simulation's random generator using the provided block. - * - * @param block a lambda that returns a RandomGenerator - */ - fun simulation(block: () -> RandomGenerator) -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt deleted file mode 100644 index 47d2766ec6..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContext.kt +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.Launcher -import it.unibo.alchemist.boundary.OutputMonitor -import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.GlobalReaction -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.LinkingRule -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.TerminationPredicate -import java.io.Serializable -import org.apache.commons.math3.random.RandomGenerator - -/** - * Main context interface for building and configuring Alchemist simulations using the DSL. - * - * This interface provides a type-safe way to configure simulations programmatically. - * It serves as the entry point for DSL users to define - * all aspects of a simulation including deployments, programs, monitors, exporters, and more. - * - * ## Usage Example - * - * ```kotlin - * simulation(incarnation, environment) { - * networkModel = ConnectWithinDistance(0.5) - * deployments { - * deploy(Grid(-5, -5, 5, 5, 0.25, 0.25)) { - * all { - * molecule = "moleculeName" - * concentration = 1.0 - * } - * } - * } - * } - * ``` - * - * @param T The type of molecule concentration used in the simulation - * @param P The type of position used in the environment, must extend [Position] - * - * @see [it.unibo.alchemist.boundary.dsl.Dsl] for creating simulation contexts - * @see [DeploymentsContextImpl] for deployment configuration - * @see [ProgramsContextImpl] for program configuration - * @see [ExporterContextImpl] for exporter configuration - * @see [LayerContextImpl] for layer configuration - */ -@Suppress("UndocumentedPublicFunction") // Detekt false positive with context parameters -interface SimulationContext, E : Environment> { - /** - * The incarnation instance that defines how molecules, nodes, and reactions are created. - * - * @see [Incarnation] for the incarnation interface - */ - val incarnation: Incarnation - - /** - * The environment where the simulation takes place. - * - * @see [Environment] - */ - val environment: E - - /** - * The launcher responsible for executing the simulation. - * - * Some implementations are available in [it.unibo.alchemist.boundary.launchers]. - * - * @see [Launcher] - */ - var launcher: Launcher - - /** - * Random number generator controlling the evolution of the events of the simulation. - * - * @see [RandomGenerator] - */ - var simulationGenerator: RandomGenerator - - /** - * Random number generator controlling the position of random deployments. - * - * @see [RandomGenerator] - */ - var scenarioGenerator: RandomGenerator - - /** - * The network model (linking rule) that defines how nodes connect in the environment. - * - * @see [LinkingRule] - */ - var networkModel: LinkingRule - - context(_: Incarnation) - fun environment(block: context(Incarnation) () -> E) - - /** - * Configures node deployments for the simulation. - * - * ## Usage Example - * ```kotlin - * deployments { - * deploy(point(0,0)) - * ... - * } - * ``` - * - * @see [DeploymentsContextImpl] to configure deployments - */ - context(_: Incarnation) - fun deployments(block: context(Incarnation, RandomGenerator, E) DeploymentsContext.() -> Unit) - - /** - * Adds a termination predicate to the simulation. - * - * @param block The termination predicate to add - * @see [TerminationPredicate] - */ - fun terminators(block: TerminatorsContext.() -> Unit) - - /** - * Adds an output monitor to the simulation. - * - * @param block The output monitor to add - * @see [OutputMonitor] - */ - fun monitors(block: OutputMonitorsContext.() -> Unit) - - /** - * Add an exporter to the simulation for data output. - * - * @param block The configuration block - * @see [ExporterContextImpl] - */ - fun exporter(block: ExporterContext.() -> Unit) - - /** - * Configures a global program. - * - * @param block the global reaction to add - * @see [GlobalReaction] - */ - fun programs(block: GlobalProgramsContext.() -> Unit) - - /** - * Schedules a block of code to execute later during the loading process. - * - * This is useful for debug purposes or for operations that need to be deferred - * - * Example: - * ```kotlin - * runLater { - * environment.nodes.forEach { node -> - * println("Node: ${node}") - * } - * } - * ``` - * - * @param block The block of code to execute later - */ - // TODO: should be removed - fun runLater(block: context(SimulationContext) () -> Unit) - - /** - * Add a spatial layer for a molecule. - * - * It is possible to define overlays (layers) of data that can be sensed - * everywhere in the environment - * - * @param block The configuration block - * @see [LayerContextImpl] - */ - fun layer(block: LayerContext.() -> Unit) - - /** - * Registers a Linear Variable for batch simulations. - * - * Example usage with a range variable: - * ```kotlin - * var myParam by variable(RangeVariable(0.0, 10.0, 0.5)) - * ``` - * - * @param source The variable source that provides the range of values - * @see [Variable] - */ - fun variable(source: Variable): VariablesContext.VariableProvider - - /** - * Registers a dependent variable that is computed from other variables. - * - * Example usage:: - * ```kotlin - * var param by variable(RangeVariable(0.0, 10.0, 0.5)) - * var computedParam by variable { param * 2.0 } - * ``` - * - * @param source A function that computes the variable value - */ - fun variable(source: () -> A): VariablesContext.DependentVariableProvider - - fun seeds(block: SeedsContext.() -> Unit) - - /** - * The context managing variables for batch simulations. - * - * @see [VariablesContext] - */ - val variablesContext: VariablesContext -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt deleted file mode 100644 index b2cedaee8a..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/SimulationContextImpl.kt +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.Launcher -import it.unibo.alchemist.boundary.OutputMonitor -import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger -import it.unibo.alchemist.boundary.launchers.DefaultLauncher -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Layer -import it.unibo.alchemist.model.LinkingRule -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.environments.Continuous2DEnvironment -import it.unibo.alchemist.model.positions.Euclidean2DPosition -import java.io.Serializable -import org.apache.commons.math3.random.MersenneTwister -import org.apache.commons.math3.random.RandomGenerator - -/** - * Main context for building and configuring a simulation. - * - * @param T The type of molecule concentration. - * @param P The type of position. - */ - -class SimulationContextImpl, E : Environment>( - override val incarnation: Incarnation, - private var environmentFactory: context(Incarnation) () -> E, -) : SimulationContext { - - private var randomGeneratorForSimulation: () -> RandomGenerator = ::defaultRandomGenerator - private var randomGeneratorForScenario: () -> RandomGenerator = ::defaultRandomGenerator - - private val simRNG by lazy { randomGeneratorForSimulation() } - private val scenarioRNG by lazy { randomGeneratorForScenario() } - - /** The environment instance (internal use). */ - override val environment: E by lazy { - context(incarnation) { - environmentFactory() - } - } - - /** - * List of build steps to execute. - */ - val buildSteps: MutableList.() -> Unit> = mutableListOf() - - /** - * List of output . - */ - val monitors: MutableList> = mutableListOf() - - private val _exporters: MutableList> = mutableListOf() - - /** - * List of exporters. - */ - val exporters: List> get() = _exporters - - override var launcher: Launcher = DefaultLauncher() - - /** - * Map of variable references. - */ - val references: MutableMap = mutableMapOf() - - private var _scenarioGenerator: RandomGenerator? = null - private var _simulationGenerator: RandomGenerator? = null - - override var scenarioGenerator: RandomGenerator - get() { - return _scenarioGenerator ?: MersenneTwister(0L).also { _scenarioGenerator = it } - } - set(value) { - buildSteps.add { this._scenarioGenerator = value } - } - - override var simulationGenerator: RandomGenerator - get() { - return _simulationGenerator ?: MersenneTwister(0L).also { _simulationGenerator = it } - } - set(value) { - buildSteps.add { this._simulationGenerator = value } - } - - private val layers: MutableMap> = HashMap() - - override var networkModel: LinkingRule - get() = environment.linkingRule - set(value) { - buildSteps.add { this.environment.linkingRule = value } - } - - /** - * The variables context for managing simulation variables. - */ - override val variablesContext = VariablesContext() - - /** - * Build a fresh new simulation context instance, and applies - * all the build steps to it. - * To ensure that each instance has - * its own variables spaces: check the [VariablesContext] documentation for more details. - * @see [VariablesContext] - */ - fun build(values: Map): SimulationContextImpl { - val batchContext = SimulationContextImpl(incarnation) - batchContext.variablesContext.variables += this.variablesContext.variables - batchContext.variablesContext.dependentVariables += this.variablesContext.dependentVariables - logger.debug("Binding variables to batchInstance: {}", values) - this.variablesContext.addReferences(values) - buildSteps.forEach { batchContext.apply(it) } - return batchContext - } - - context(_: Incarnation) - override fun deployments( - block: context(Incarnation, RandomGenerator, E) DeploymentsContext.() -> Unit, - ) { - buildSteps.add { - logger.debug("Configuring deployments inside {}", this) - context(scenarioRNG) { - DeploymentsContextImpl(simRNG).apply { - context(environment) { - block() - } - } - } - } - } - - context(_: Incarnation) - override fun environment(block: context(Incarnation) () -> E) { - environmentFactory = block - } - - override fun monitors(block: OutputMonitorsContext.() -> Unit) { - buildSteps.add { OutputMonitorsContextImpl(this).block() } - } - - override fun exporter(block: ExporterContext.() -> Unit) { - buildSteps.add { this._exporters.add(ExporterContextImpl(this).apply(block)) } - } - - override fun programs(block: GlobalProgramsContext.() -> Unit) { - buildSteps.add { GlobalProgramsContextImpl(this).block() } - } - - override fun runLater(block: context(SimulationContext)() -> Unit) { - buildSteps.add { block() } - } - - override fun layer(block: LayerContext.() -> Unit) { - buildSteps.add { - val l = LayerContextImpl().apply(block) - val layer = requireNotNull(l.layer) { "Layer must be specified" } - val moleculeName = requireNotNull(l.molecule) { "Molecule must be specified" } - require(!this.layers.containsKey(moleculeName)) { - "Inconsistent layer definition for molecule $moleculeName. " + - "There must be a single layer per molecule" - } - val molecule = incarnation.createMolecule(moleculeName) - logger.debug("Adding layer for molecule {}: {}", moleculeName, layer) - this.layers[moleculeName] = layer - this.environment.addLayer(molecule, layer) - } - } - - override fun seeds(block: SeedsContext.() -> Unit) { - val seedContext = object : SeedsContext { - override fun simulation(seed: Long) = simulation { defaultRandomGenerator(seed) } - - override fun scenario(seed: Long) = scenario { defaultRandomGenerator(seed) } - - override fun simulation(block: () -> RandomGenerator) { - randomGeneratorForSimulation = block - } - - override fun scenario(block: () -> RandomGenerator) { - randomGeneratorForScenario = block - } - } - seedContext.block() - } - - override fun terminators(block: TerminatorsContext.() -> Unit) { - @Suppress("UNCHECKED_CAST") - buildSteps.add { TerminatorsContextImpl(this).block() } - } - - override fun variable(source: Variable): VariablesContext.VariableProvider = - variablesContext.register(source) - - override fun variable(source: () -> A): VariablesContext.DependentVariableProvider = - variablesContext.dependent(source) - - private companion object { - fun defaultRandomGenerator(seed: Long = 0L): RandomGenerator = MersenneTwister(seed) - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/TerminatorsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/TerminatorsContext.kt deleted file mode 100644 index 2a0bc66008..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/TerminatorsContext.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.dsl.AlchemistDsl -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.TerminationPredicate - -/** - * Context for configuring termination predicates in a simulation. - * - * @param T The type of molecule concentration. - * @param P The type of position. - */ -@AlchemistDsl -interface TerminatorsContext> { - /** The parent simulation context. */ - val ctx: SimulationContext - - /** - * Adds a termination predicate to the simulation. - * - * @param this The termination predicate to add. - */ - operator fun TerminationPredicate<*, *>.unaryPlus() -} - -/** - * Implementation of [TerminatorsContext]. - * - * @param T The type of molecule concentration. - * @param P The type of position. - */ -class TerminatorsContextImpl>(override val ctx: SimulationContext) : - TerminatorsContext { - @Suppress("UNCHECKED_CAST") - override fun TerminationPredicate<*, *>.unaryPlus() { - ctx.environment.addTerminator(this as TerminationPredicate) - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt deleted file mode 100644 index f60078b0cc..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/model/VariablesContext.kt +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.model - -import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger -import java.io.Serializable -import kotlin.properties.ReadOnlyProperty -import kotlin.properties.ReadWriteProperty -import kotlin.reflect.KProperty - -/** - * Context for managing variables in a simulation. - */ -class VariablesContext { - - /** Map of default variable values. */ - val defaults: MutableMap = mutableMapOf() - - /** Thread-local map of variable references. */ - val references = object : ThreadLocal>() { - override fun initialValue(): Map { - logger.debug("Initializing variable references with defaults: {}", defaults) - return defaults.toMap() - } - } - - /** - * Map of registered variables. - */ - val variables: MutableMap> = mutableMapOf() - - /** - * Map of dependent variables. - */ - val dependentVariables: MutableMap Any> = mutableMapOf() - - /** - * Adds new variable references to the current thread-local context. - * Since each simulation may run in its own thread, this ensures that each simulation - * has its own set of variable references, while still using the same variable definitions. - * - * @param newRefs Map of new variable references to add to the default/existing ones. - */ - fun addReferences(newRefs: Map) { - val currMap = references.get() - val updatedMap = currMap.toMutableMap().also { m -> - m.putAll(newRefs.mapValues { it.value as Any }) - } - references.set(updatedMap) - } - - /** - * Registers a variable provider. - * - * @param source The variable source. - * @return A variable provider. - */ - fun register(source: Variable): VariableProvider = VariableProvider(source) - - /** - * Registers a dependent variable provider. - * - * @param source The dependent variable source function. - * @return A dependent variable provider. - */ - fun dependent(source: () -> T): DependentVariableProvider = DependentVariableProvider(source) - - /** - * Provider for dependent variables that are computed from a source function. - * - * @param T The type of the variable value. - * @param source The function that provides the variable value. - */ - inner class DependentVariableProvider(private val source: () -> T) { - /** - * Provides a delegate for property delegation. - * - * @param thisRef The receiver object. - * @param prop The property metadata. - * @return A read-only property delegate. - */ - operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty { - check(!variables.containsKey(prop.name) && !dependentVariables.contains(prop.name)) { - "Variable ${prop.name} already exists" - } - dependentVariables[prop.name] = source - return DependentRef(source) - } - } - - /** - * Read-only property delegate for dependent variables. - * - * @param T The type of the variable value. - * @param source The function that provides the variable value. - */ - class DependentRef(private val source: () -> T) : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): T = source() - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: T): Unit = - error("Not allowed to assign a value to the variable ${property.name}") - } - - /** - * Provider for variables that are registered with a Variable source. - * - * @param T The type of the variable value. - * @param source The variable source. - */ - inner class VariableProvider(private val source: Variable<*>) { - /** - * Provides a delegate for property delegation. - * - * @param thisRef The receiver object. - * @param prop The property metadata. - * @return A read-only property delegate. - */ - operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty { - check(!variables.containsKey(prop.name) && !dependentVariables.contains(prop.name)) { - "Variable ${prop.name} already exists" - } - logger.debug("Registering variable: {}", prop.name) - variables[prop.name] = source - defaults[prop.name] = source.default - return Ref() - } - } - - /** - * Read-write property delegate for variables. - * - * @param T The type of the variable value. - */ - inner class Ref : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): T { - check(references.get().contains(property.name)) { - "Variable ${property.name} has no defined value" - } - @Suppress("UNCHECKED_CAST") - return references.get()[property.name] as T - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: T): Unit = - error("Not allowed to assign a value to the variable ${property.name}") - } -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt deleted file mode 100644 index 69caebe692..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/util/LoadingSystemLogger.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2010-2025, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.dsl.util - -import it.unibo.alchemist.boundary.dsl.DSLLoader -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -internal object LoadingSystemLogger { - val logger: Logger = LoggerFactory.getLogger(DSLLoader::class.java) -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ActionableContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ActionableContext.kt new file mode 100644 index 0000000000..78a274203c --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ActionableContext.kt @@ -0,0 +1,39 @@ +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.model.Action +import it.unibo.alchemist.model.Actionable +import it.unibo.alchemist.model.Condition + +/** + * DSL entry-point for configuring an [Actionable] by attaching [Action]s and [Condition]s. + * + * This object is intended to be used with Kotlin context receivers, so that the target [Actionable] instance + * is implicitly available in the current scope. + * + * Both [action] and [condition] mutate the current [Actionable] by appending the provided element to its internal + * collections. Ordering is preserved and duplicates are allowed. + */ +// TODO: Detekt false positive. Remove once Detekt supports context parameters. +@Suppress("UndocumentedPublicFunction") +object ActionableContext { + + /** + * Appends the given [Action] to the current [Actionable]. + * + * @param action the action to add. + */ + context(actionable: Actionable) + fun action(action: Action) { + actionable.actions += action + } + + /** + * Appends the given [Condition] to the current [Actionable]. + * + * @param condition the condition to add. + */ + context(actionable: Actionable) + fun condition(condition: Condition) { + actionable.conditions += condition + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt new file mode 100644 index 0000000000..b34d4e3b5f --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.boundary.DependentVariable +import it.unibo.alchemist.boundary.Exporter +import it.unibo.alchemist.boundary.Extractor +import it.unibo.alchemist.boundary.Launcher +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.OutputMonitor +import it.unibo.alchemist.boundary.Variable +import it.unibo.alchemist.boundary.exporters.GlobalExporter +import it.unibo.alchemist.boundary.launchers.DefaultLauncher +import it.unibo.alchemist.core.Engine +import it.unibo.alchemist.core.Simulation +import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.GeoPosition +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Neighborhood +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.PositionBasedFilter +import it.unibo.alchemist.model.environments.AbstractEnvironment +import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.environments.continuous2DEnvironment +import it.unibo.alchemist.model.positions.Euclidean2DPosition +import java.io.Serializable +import kotlin.properties.ReadOnlyProperty +import org.apache.commons.math3.random.MersenneTwister +import org.apache.commons.math3.random.RandomGenerator +import org.danilopianini.util.SpatialIndex +import org.slf4j.LoggerFactory + +@Suppress("UNCHECKED_CAST") +operator fun > PositionBasedFilter<*>.contains(position: P): Boolean = + (this as PositionBasedFilter

).contains(position) + +context(_: Incarnation) +fun SimulationContext.environment( + block: context(Continuous2DEnvironment) EnvironmentContext.() -> Unit, +) = environment(continuous2DEnvironment(), block) + +fun , I : Incarnation> simulation( + incarnation: I, + block: context(I) SimulationContext.() -> Unit, +): Loader = object : Loader { + + private val logger = LoggerFactory.getLogger("Alchemist Kotlin DSL Loader") + override var constants: Map = emptyMap() + override val remoteDependencies: List get() = TODO("Not yet implemented") + override var launcher: Launcher = DefaultLauncher() + override val dependentVariables: Map> = emptyMap() + override var variables: Map> = emptyMap() + val defaultEnvironment = getWithTyped(emptyMap()) + + @Suppress("UNCHECKED_CAST") + override fun > getWith(values: Map): Simulation = + (if(values.isEmpty()) defaultEnvironment else getWithTyped(values)) as Simulation + + private fun getWithTyped(values: Map): Simulation { + logger.debug("Creating simulation with variables: {}", values) + val loader = this + val noIndex = object : SpatialIndex> { + override val dimensions: Int = 2 + override fun insert(element: Node, vararg position: Double) = Unit + override fun remove(element: Node, vararg position: Double) = false + override fun move(element: Node, start: DoubleArray, end: DoubleArray) = false + override fun query(vararg parallelotope: DoubleArray) = emptyList>() + } + var theEnvironment: Environment = object : AbstractEnvironment(incarnation, noIndex) { + override fun computeActualInsertionPosition(node: Node, p: P): P = nope() + override fun nodeAdded(node: Node, position: P, neighborhood: Neighborhood) = nope() + override val dimensions: Int = 2 + override val offset: DoubleArray = DoubleArray(dimensions) { 0.0 } + override val size: DoubleArray = DoubleArray(dimensions) { 1.0 } + override fun makePosition(vararg coordinates: Number): P = nope() + override fun makePosition(coordinates: DoubleArray) = nope() + override fun moveNodeToPosition(node: Node, newPosition: P) = nope() + fun nope(): Nothing = error( + "The empty environment cannot generate positions, and does not support the insertion of nodes." + ) + } + val exporters = mutableListOf>() + val monitors = mutableListOf>() + context(incarnation) { + object : SimulationContext { + + var launcherHasNotBeenSet = true + var environmentHasNotBeenSet = true + lateinit var simulationRNG: RandomGenerator + lateinit var scenarioRNG: RandomGenerator + + override fun > environment( + environment: E, + block: context(E) EnvironmentContext.() -> Unit, + ) { + if (!this::simulationRNG.isInitialized) { + simulationRNG = MersenneTwister(0L) + } + if (!this::scenarioRNG.isInitialized) { + scenarioRNG = MersenneTwister(0L) + } + check(environmentHasNotBeenSet) { + "Only one environment can be set, currently set: $theEnvironment" + } + theEnvironment = environment + environmentHasNotBeenSet = false + context(environment, simulationRNG) { + check(contextOf() == simulationRNG) + object : EnvironmentContext { + override fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) { + check(contextOf() == simulationRNG) + context(scenarioRNG) { + object : DeploymentsContext { + context(randomGenerator: RandomGenerator, environment: Environment) + override fun > deploy( + deployment: Deployment

, + nodeFactory: (P) -> Node, + block: context(RandomGenerator, Node) DeploymentContext.() -> Unit, + ) { + check(contextOf() == scenarioRNG) + deployment.forEach { position -> + context(simulationRNG) { + check(contextOf() == simulationRNG) + val node: Node = nodeFactory(position) + context(node) { + object : DeploymentContext { + override val position: P get() = position + }.block() + } + environment.addNode(node, position) + } + } + } + }.block() + } + } + }.block() + } + } + + override fun exportWith(exporter: Exporter, block: ExporterContext.() -> Unit) { + val extractors = mutableListOf>() + object : ExporterContext { + override fun Extractor<*>.unaryMinus() { + extractors += this + } + }.block() + exporter.bindDataExtractors(extractors) + exporters += exporter + } + + override fun scenarioRandomGenerator(randomGenerator: RandomGenerator) { + checkSeedCanBeSet() + scenarioRNG = randomGenerator + } + + override fun simulationRandomGenerator(randomGenerator: RandomGenerator) { + checkSeedCanBeSet() + simulationRNG = randomGenerator + } + + override fun monitor(monitor: OutputMonitor) { + monitors += monitor + } + + override fun launcher(launcher: Launcher) { + check(launcherHasNotBeenSet) { + "Only one launcher can be set, currently set: ${loader.launcher}" + } + loader.launcher = launcher + } + + override fun variable(variable: Variable): ReadOnlyProperty = + ReadOnlyProperty { thisRef, property -> + variables += property.name to variable + @Suppress("UNCHECKED_CAST") + values.getOrDefault(property.name, variable.default) as V + } + + fun checkSeedCanBeSet() { + check(environmentHasNotBeenSet) { + "Seeds must be set before the environment is defined to preserve reproducibility" + } + } + }.block() + } + check(variables.keys.containsAll(values.keys)) { + val undefinedVariables = values.keys - variables.keys + """ + The following variables provided in input have no corresponding variable defined in the simulation context: + $undefinedVariables + The available variables are: ${variables.keys} + """.trimIndent() + } + val theSimulation: Simulation = Engine(theEnvironment) + if (exporters.isNotEmpty()) { + theSimulation.addOutputMonitor(GlobalExporter(exporters)) + } + monitors.forEach { monitor -> theSimulation.addOutputMonitor(monitor) } + return theSimulation + } +} + +fun > simulationOnMap( + incarnation: I, + block: context(I) SimulationContext.() -> Unit, +) = simulation(incarnation, block) + +fun > simulation2D( + incarnation: I, + block: context(I) SimulationContext.() -> Unit, +) = simulation(incarnation, block) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistScript.kt similarity index 95% rename from alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt rename to alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistScript.kt index 7395db65fc..efbbc55153 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/dsl/scripting/AlchemistScript.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistScript.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -7,7 +7,7 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.boundary.dsl.scripting +package it.unibo.alchemist.boundary.kotlindsl import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.api.ScriptAcceptedLocation @@ -34,7 +34,7 @@ interface AlchemistScript */ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ defaultImports( - "it.unibo.alchemist.boundary.dsl.Dsl.simulation", + "it.unibo.alchemist.boundary.kotlindsl.*", "it.unibo.alchemist.boundary.dsl.Dsl.incarnation", "it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.*", "it.unibo.alchemist.boundary.dsl.model.Incarnation.*", diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ContentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ContentContext.kt new file mode 100644 index 0000000000..33156f5dbc --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ContentContext.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Molecule +import it.unibo.alchemist.model.Node + +/** + * DSL utilities for defining the initial contents of a [Node]. + * + * This context provides helpers to: + * - build concentrations using the current [Incarnation]; + * - assign concentrations to a [Node] using the unary minus operator. + * + * The API is based on Kotlin context receivers: the required [Incarnation] and/or [Node] are expected to be + * available in the current context. + */ +// TODO: Detekt false positive. Remove once Detekt supports context parameters. +@Suppress("UndocumentedPublicFunction") +object ContentContext { + + /** + * Creates a concentration value using the current [Incarnation]. + * + * This is a convenience wrapper around [Incarnation.createConcentration] to keep DSL code concise. + * + * @param origin an optional value used by the [Incarnation] to derive the concentration. + * @return a concentration instance of type [T]. + */ + context(incarnation: Incarnation) + fun concentrationOf(origin: Any?): T = incarnation.createConcentration(origin) + + /** + * Assigns a concentration to the current [Node] for the given [Molecule]. + * + * This operator enables concise DSL statements by interpreting `-(molecule to concentration)` as + * "set the concentration of this molecule on the current node". + * + * @receiver a pair `(molecule, concentration)` to assign. + */ + context(node: Node) + operator fun Pair.unaryMinus() { + node.setConcentration(first, second) + } + + /** + * Assigns a default concentration for this [Molecule] to the current [Node]. + * + * The concentration is created via [Incarnation.createConcentration] with no explicit origin. + * + * @receiver the molecule whose concentration should be set. + */ + context(incarnation: Incarnation, _: Node) + operator fun Molecule.unaryMinus() = -Pair(this, incarnation.createConcentration()) + + /** + * Assigns a default concentration for the molecule identified by this string to the current [Node]. + * + * The [Molecule] is created via [Incarnation.createMolecule], while the concentration is created via + * [Incarnation.createConcentration] with no explicit origin. + * + * @receiver the molecule name to create and set. + */ + context(incarnation: Incarnation, _: Node) + operator fun String.unaryMinus() = -Pair(incarnation.createMolecule(this), incarnation.createConcentration()) + + /** + * Assigns the provided concentration to the molecule identified by the given name on the current [Node]. + * + * The molecule is created via [Incarnation.createMolecule]. + * + * @receiver a pair `(moleculeName, concentration)` to assign. + */ + context(incarnation: Incarnation, _: Node) + operator fun Pair.unaryMinus() = -Pair(incarnation.createMolecule(first), second) +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt new file mode 100644 index 0000000000..4ca0973fb6 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.NodeProperty +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.Reaction +import it.unibo.alchemist.model.TimeDistribution +import org.apache.commons.math3.random.RandomGenerator + +/** + * DSL scope for configuring a single node during a deployment. + * + * A [DeploymentContext] is typically entered once per deployed position, and provides: + * - the target [position] being deployed; + * - utilities to create and attach reactions (optionally configuring actions/conditions); + * - utilities to initialize node contents and attach [NodeProperty] instances. + * + * Most operations rely on Kotlin context receivers, so the relevant [Incarnation], [Environment], + * [RandomGenerator], and [Node] instances are expected to be available in the surrounding scope. + * + * @param T the concentration type used by the simulation. + * @param P the position type used by the environment. + */ +// TODO: Detekt false positive. Remove once Detekt supports context parameters. +@Suppress("UndocumentedPublicFunction") +interface DeploymentContext> { + + /** + * The position where the node is being deployed. + * + * This is the position currently produced by the deployment strategy and that will be passed to + * the environment insertion logic. + */ + val position: P + + /** + * Enters a [TimeDistributionContext] bound to the provided [timeDistribution]. + * + * The [block] is executed with [timeDistribution] as a context receiver, enabling reaction definition + * utilities that share this distribution. + * + * @param timeDistribution the time distribution to use for reactions configured inside [block]. + * @param block the configuration block for defining reactions sharing [timeDistribution]. + */ + fun > timeDistribution( + timeDistribution: TimeDistributionType, + block: context(TimeDistributionType) TimeDistributionContext.() -> Unit, + ) { + context(timeDistribution) { + object : TimeDistributionContext { }.block() + } + } + + /** + * Enters a [TimeDistributionContext] using a time distribution derived from [parameter]. + * + * If [parameter] is already a [TimeDistribution], it is used as-is. Otherwise, a new distribution is created + * via [Incarnation.createTimeDistribution], passing [parameter] through to the incarnation. + * + * @param parameter either a concrete [TimeDistribution] instance, an incarnation-specific descriptor, or `null`. + * @param block the configuration block for defining reactions sharing the selected time distribution. + */ + @Suppress("UNCHECKED_CAST") + context( + incarnation: Incarnation, + randomGenerator: RandomGenerator, + environment: Environment, + node: Node + ) + fun withTimeDistribution( + parameter: Any? = null, + block: context(TimeDistribution) TimeDistributionContext.() -> Unit, + ) = timeDistribution>( + parameter as? TimeDistribution ?: makeTimeDistribution(parameter), + block, + ) + + /** + * Convenience utility to create and register a reaction on the current node. + * + * A time distribution is obtained through [withTimeDistribution], using [timeDistribution] as parameter. + * The reaction is then created via [Incarnation.createReaction], using [program] as an incarnation-specific + * descriptor (or `null` to delegate the choice to the incarnation), and finally registered on the node. + * + * The optional [block] can be used to attach actions and conditions through [ActionableContext]. + * + * @param program an incarnation-specific reaction/program descriptor, possibly `null`. + * @param timeDistribution either a concrete [TimeDistribution] instance, an incarnation-specific descriptor, or `null`. + * @param block an optional configuration block for actions and conditions. + */ + context( + incarnation: Incarnation, + randomGenerator: RandomGenerator, + environment: Environment, + node: Node + ) + fun program( + program: String? = null, + timeDistribution: Any? = null, + block: context(Reaction) ActionableContext.() -> Unit = { }, + ) = withTimeDistribution(timeDistribution) { + program(program, block) + } + + /** + * Configures the initial contents of the current node. + * + * The [block] is executed with the current [Incarnation] available as a context receiver and with + * [ContentContext] as receiver, enabling concise content creation and assignment utilities. + * + * @param block the configuration block for node contents. + */ + context(_: Incarnation, _: Node) + fun contents(block: context(Incarnation) ContentContext.() -> Unit) { + ContentContext.block() + } + + /** + * Attaches a [NodeProperty] to the current node. + * + * @param property the property instance to add to the node. + */ + context(node: Node) + fun nodeProperty(property: NodeProperty) { + node.addProperty(property) + } + + private companion object { + + /** + * Creates a [TimeDistribution] through the current [Incarnation]. + * + * The [parameter] is forwarded to [Incarnation.createTimeDistribution] and its interpretation depends on + * the concrete incarnation. + * + * @param parameter an incarnation-specific descriptor, or `null`. + * @return a time distribution suitable for scheduling reactions on the given [node] in the given [environment]. + */ + context( + incarnation: Incarnation, + randomGenerator: RandomGenerator, + environment: Environment, + node: Node + ) + fun > makeTimeDistribution(parameter: Any? = null): TimeDistribution = + incarnation.createTimeDistribution( + randomGenerator, + environment, + node, + parameter, + ) + + /** + * Creates a [Reaction] through the current [Incarnation] using the provided [timeDistribution]. + * + * Note: the [descriptor] parameter is currently ignored, and the reaction is created with a `null` + * program descriptor, delegating program selection to the incarnation. + * + * @param descriptor an optional descriptor that is currently not used. + * @return a reaction created by the incarnation for the given context. + */ + context( + incarnation: Incarnation, + randomGenerator: RandomGenerator, + environment: Environment, + node: Node, + timeDistribution: TimeDistribution + ) + fun > makeReaction(descriptor: String?): Reaction = incarnation.createReaction( + randomGenerator, + environment, + node, + timeDistribution, + null, + ) + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentsContext.kt new file mode 100644 index 0000000000..35321257ad --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentsContext.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import org.apache.commons.math3.random.RandomGenerator + +/** + * DSL scope for instantiating and configuring nodes produced by a [Deployment]. + * + * A [Deployment] enumerates a set of positions. For each produced position, an implementation of this context is + * expected to: + * - create a [Node] (either through a caller-provided factory or via an [Incarnation]); + * - enter a [DeploymentContext] to configure node contents, reactions, and properties; + * - (typically) insert the configured node into the current [Environment]. + * + * This interface is based on Kotlin context receivers: the relevant [RandomGenerator] and [Environment] (and, in the + * overload that creates nodes via incarnation, also the [Incarnation]) must be available in the surrounding scope. + */ +// TODO: Detekt false positive. Remove once Detekt supports context parameters. +@Suppress("UndocumentedPublicFunction") +interface DeploymentsContext { + + /** + * Deploys nodes according to the provided [deployment], creating each node through [nodeFactory] and optionally + * configuring it through [block]. + * + * The [block] is invoked once per deployed position, after the node has been created and while a suitable DSL scope + * is active. Within [block], a [DeploymentContext] is provided as receiver, and the current [RandomGenerator] and + * the created [Node] are available as context receivers. + * + * @param deployment the deployment strategy producing the positions where nodes should be created. + * @param nodeFactory a factory used to create a node for each deployed position. + * @param block an optional per-node configuration block. + */ + context(randomGenerator: RandomGenerator, environment: Environment) + fun > deploy( + deployment: Deployment

, + nodeFactory: (P) -> Node, + block: context(RandomGenerator, Node) DeploymentContext.() -> Unit = {}, + ) + + /** + * Deploys nodes according to the provided [deployment], creating each node via the current [incarnation] and + * optionally configuring it through [block]. + * + * Node creation is delegated to [Incarnation.createNode], using the current [randomGenerator] and [environment]. + * The optional [nodeParameter] is forwarded to the incarnation and its meaning depends on the concrete incarnation. + * + * @param deployment the deployment strategy producing the positions where nodes should be created. + * @param nodeParameter an optional incarnation-specific node descriptor, possibly `null`. + * @param block an optional per-node configuration block. + */ + context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment) + fun > deploy( + deployment: Deployment

, + nodeParameter: String? = null, + block: context(RandomGenerator, Node) DeploymentContext.() -> Unit = {}, + ) = deploy(deployment, { incarnation.createNode(randomGenerator, environment, nodeParameter) }, block) +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/EnvironmentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/EnvironmentContext.kt new file mode 100644 index 0000000000..aa777fb6b5 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/EnvironmentContext.kt @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.GlobalReaction +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Layer +import it.unibo.alchemist.model.LinkingRule +import it.unibo.alchemist.model.Molecule +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.TerminationPredicate +import it.unibo.alchemist.model.TimeDistribution +import it.unibo.alchemist.model.linkingrules.CombinedLinkingRule +import it.unibo.alchemist.model.linkingrules.NoLinks +import org.apache.commons.math3.random.RandomGenerator + +/** + * DSL scope for configuring an [Environment] within a simulation scenario. + * + * This context groups environment-level configuration concerns, including: + * - deploying nodes through a [DeploymentsContext]; + * - registering global reactions; + * - registering layers (molecule → [Layer] mappings); + * - configuring the environment network model ([LinkingRule]); + * - registering termination predicates. + * + * Most operations rely on Kotlin context receivers: the relevant [Environment] (and, when applicable, + * the [Incarnation] and/or [RandomGenerator]) must be available in the surrounding scope. + * + * @param T the concentration type used by the simulation. + * @param P the position type used by the environment. + */ +// TODO: Detekt false positive. Remove once Detekt supports context parameters. +@Suppress("UndocumentedPublicFunction") +interface EnvironmentContext> { + + /** + * Enters the node deployment DSL. + * + * The provided [block] is executed with a [RandomGenerator] available as a context receiver and with + * [DeploymentsContext] as receiver, allowing the scenario to create and configure nodes produced by + * one or more [it.unibo.alchemist.model.Deployment] strategies. + * + * Implementations are expected to ensure a consistent usage of random generators for reproducibility. + * + * @param block the deployment configuration block. + */ + fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) + + /** + * Registers a [GlobalReaction] in the current [Environment] and optionally configures it. + * + * The [block], if provided, is executed with [globalReaction] as a context receiver and with + * [ActionableContext] as receiver, enabling the addition of actions and conditions. + * + * The [timeDistribution] parameter is currently not used by this function. The expectation is that + * the provided [globalReaction] is already configured with the intended scheduling strategy (if any), + * or that the distribution is otherwise bound externally. + * + * @param timeDistribution a time distribution associated with the global program; currently ignored. + * @param globalReaction the global reaction to register. + * @param block an optional configuration block for actions and conditions. + */ + context(environment: Environment) + fun globalProgram( + timeDistribution: TimeDistribution, + globalReaction: GlobalReaction, + block: context(GlobalReaction) ActionableContext.() -> Unit = {}, + ) { + context(globalReaction) { + ActionableContext.block() + } + environment.addGlobalReaction(globalReaction) + } + + /** + * Registers a [Layer] associated with the given [molecule] in the current [Environment]. + * + * Layers are used to provide environment-wide values (e.g., fields or maps) that can be queried by nodes + * or reactions via the associated molecule. + * + * @param molecule the molecule acting as key for the layer. + * @param layer the layer instance to register. + */ + context(environment: Environment) + fun layer(molecule: Molecule, layer: Layer) = environment.addLayer(molecule, layer) + + /** + * Registers a [Layer] associated with a molecule identified by [molecule] in the current [Environment]. + * + * The molecule is created via [Incarnation.createMolecule]. The meaning of a `null` molecule name, if any, + * depends on the concrete incarnation. + * + * @param molecule the molecule name, possibly `null` (incarnation-dependent semantics). + * @param layer the layer instance to register. + */ + context(incarnation: Incarnation, environment: Environment) + fun layer(molecule: String? = null, layer: Layer) = layer(incarnation.createMolecule(molecule), layer) + + /** + * Configures (or extends) the environment network model by adding the provided [model]. + * + * The current linking rule is updated as follows: + * - if the environment currently uses [NoLinks], it is replaced with [model]; + * - if the environment currently uses [CombinedLinkingRule], [model] is appended to its sub-rules; + * - otherwise, the existing rule and [model] are combined into a new [CombinedLinkingRule]. + * + * @param model the linking rule to set or append. + */ + context(environment: Environment) + fun networkModel(model: LinkingRule) = when (val currentRule = environment.linkingRule) { + is NoLinks -> environment.linkingRule = model + is CombinedLinkingRule -> environment.linkingRule = CombinedLinkingRule(currentRule.subRules + model) + else -> environment.linkingRule = CombinedLinkingRule(listOf(environment.linkingRule, model)) + } + + /** + * Registers a [TerminationPredicate] in the current [Environment]. + * + * @param terminator the termination predicate to add. + */ + context(environment: Environment) + fun terminator(terminator: TerminationPredicate) = environment.addTerminator(terminator) +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ExporterContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ExporterContext.kt new file mode 100644 index 0000000000..7fb2537787 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ExporterContext.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.boundary.Extractor +import it.unibo.alchemist.model.Position + +/** + * DSL scope for configuring exporters by collecting [Extractor] instances. + * + * Implementations of this context are expected to translate unary-minus applications on extractors into + * registrations/collection operations (e.g., adding the extractor to a list that will later be bound to + * an exporter). + * + * The type parameters are carried to keep the DSL aligned with the simulation types, even though this + * context only deals with extractors at the boundary layer. + * + * @param T the concentration type used by the simulation. + * @param P the position type used by the environment. + */ +interface ExporterContext> { + + /** + * Registers this [Extractor] in the current exporter configuration. + * + * This operator is intended to provide concise DSL syntax, where applying unary minus to an extractor + * means "include this extractor among those used by the exporter". + */ + operator fun Extractor<*>.unaryMinus() +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt new file mode 100644 index 0000000000..d23b45c928 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.boundary.Exporter +import it.unibo.alchemist.boundary.Launcher +import it.unibo.alchemist.boundary.OutputMonitor +import it.unibo.alchemist.boundary.Variable +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Position +import org.apache.commons.math3.random.MersenneTwister +import org.apache.commons.math3.random.RandomGenerator +import java.io.Serializable +import kotlin.properties.ReadOnlyProperty + +/** + * Top-level DSL scope for defining a simulation scenario. + * + * A [SimulationContext] is responsible for collecting all scenario components that are needed to build a runnable + * simulation, including: + * - the [Environment] and its configuration (deployments, layers, global programs, network model, terminators); + * - exporters and output monitors; + * - the [Launcher] used to run the simulation; + * - scenario variables, exposed as delegated read-only properties. + * + * Implementations typically distinguish between two random generators: + * - a *scenario* generator, used while constructing the scenario (e.g., during deployments or initialization); + * - a *simulation* generator, used for components that require randomness tied to simulation execution. + * + * @param T the concentration type used by the simulation. + * @param P the position type used by the environment. + */ +interface SimulationContext> { + + /** + * Sets the simulation [environment] and configures it through [block]. + * + * The [block] is executed with the provided environment as a context receiver, and with an [EnvironmentContext] + * as receiver, enabling environment-level configuration (deployments, layers, global programs, linking rules, + * terminators). + * + * @param environment the environment instance to use for the simulation. + * @param block the environment configuration block. + */ + fun > environment(environment: E, block: context(E) EnvironmentContext.() -> Unit) + + /** + * Registers an [Exporter] and configures which [it.unibo.alchemist.boundary.Extractor] instances it should use. + * + * The [block] is executed with an [ExporterContext] receiver, typically allowing extractors to be collected via + * unary-minus notation and then bound to the exporter. + * + * @param exporter the exporter to register. + * @param block the exporter configuration block. + */ + fun exportWith(exporter: Exporter, block: ExporterContext.() -> Unit) + + /** + * Sets the random generator used during scenario construction. + * + * The scenario random generator is meant for operations that happen while building the scenario configuration, + * such as deployments and initialization steps performed before the simulation starts. + * + * @param randomGenerator the random generator to use for scenario construction. + */ + fun scenarioRandomGenerator(randomGenerator: RandomGenerator) + + /** + * Sets the scenario random generator to a [MersenneTwister] initialized with [seed]. + * + * This is a convenience method equivalent to calling [scenarioRandomGenerator] with a new [MersenneTwister]. + * + * @param seed the seed to initialize the generator. + */ + fun scenarioSeed(seed: Long) = scenarioRandomGenerator(MersenneTwister(seed)) + + /** + * Sets the random generator used for simulation-related components. + * + * This generator is intended for components created as part of the scenario that require randomness associated + * with simulation execution (e.g., reactions/time distributions or other simulation-time behaviors), + * depending on the implementation. + * + * @param randomGenerator the random generator to use for simulation-related components. + */ + fun simulationRandomGenerator(randomGenerator: RandomGenerator) + + /** + * Sets the simulation random generator to a [MersenneTwister] initialized with [seed]. + * + * This is a convenience method equivalent to calling [simulationRandomGenerator] with a new [MersenneTwister]. + * + * @param seed the seed to initialize the generator. + */ + fun simulationSeed(seed: Long) = simulationRandomGenerator(MersenneTwister(seed)) + + /** + * Registers an [OutputMonitor] to observe the simulation execution. + * + * @param monitor the monitor to add. + */ + fun monitor(monitor: OutputMonitor) + + /** + * Sets the [Launcher] used to run the simulation. + * + * @param launcher the launcher to use. + */ + fun launcher(launcher: Launcher) + + /** + * Declares a scenario [Variable] and returns a read-only property delegate that provides its value. + * + * Implementations typically associate the variable with the name of the delegated property and resolve its value + * from the runtime-provided variable map, falling back to [Variable.default] when no override is provided. + * + * @param variable the variable definition. + * @return a property delegate providing the resolved variable value. + */ + fun variable(variable: Variable): ReadOnlyProperty +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt new file mode 100644 index 0000000000..f8db8a7cd2 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.TerminationPredicate + +/** + * DSL utilities for registering [TerminationPredicate] instances in an [Environment]. + * + * This context is meant to be used with Kotlin context receivers, requiring an [Environment] to be available + * in the surrounding scope. The unary minus operator provides a compact notation for adding terminators. + */ +// TODO: Detekt false positive. Remove once Detekt supports context parameters. +@Suppress("UndocumentedPublicFunction") +object TerminatorsContext { + + /** + * Registers this [TerminationPredicate] into the current [Environment]. + * + * This operator enables concise DSL statements by interpreting `-predicate` as + * "add this predicate as a terminator to the current environment". + * + * @receiver the termination predicate to register. + */ + context(environment: Environment) + operator fun > TerminationPredicate.unaryMinus() = environment.addTerminator(this) +} + diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TimeDistributionContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TimeDistributionContext.kt new file mode 100644 index 0000000000..d2ef2dbf32 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TimeDistributionContext.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.Reaction +import it.unibo.alchemist.model.TimeDistribution +import org.apache.commons.math3.random.RandomGenerator + +/** + * DSL scope for defining one or more [Reaction]s that share a common [TimeDistribution]. + * + * This scope is meant to be used via Kotlin context receivers: a [TimeDistribution] (and, for some operations, + * additional objects such as [Node], [Incarnation], [Environment], and [RandomGenerator]) must be available + * in the surrounding context. + * + * The provided helpers support two common workflows: + * - registering an already-built [Reaction] on the current [Node]; + * - creating a [Reaction] from an incarnation-specific program descriptor and registering it on the current [Node]. + * + * In both cases, an optional configuration block can be provided to attach [it.unibo.alchemist.model.Action]s + * and [it.unibo.alchemist.model.Condition]s via [ActionableContext]. + */ +// TODO: Detekt false positive. Remove once Detekt supports context parameters. +@Suppress("UndocumentedPublicFunction", "UndocumentedPublicProperty") +interface TimeDistributionContext> { + + /** + * Provides access to the current [TimeDistribution] context receiver. + * + * This property mainly exists to allow explicit access to the time distribution from within nested DSL blocks, + * without having to refer to the context receiver name directly. + */ + context(timeDistribution: TimeDistribution) + val timeDistribution: TimeDistribution get() = timeDistribution + + /** + * Registers an existing [reaction] on the current [Node] and optionally configures it. + * + * The [block], if provided, is executed in a scope where: + * - the [reaction] is available as a context receiver, and + * - [ActionableContext] is the receiver, enabling the addition of actions and conditions. + * + * After the configuration block is executed, the reaction is added to the current node via [Node.addReaction]. + * + * @param reaction the reaction to configure and register. + * @param block an optional configuration block for actions and conditions. + */ + context(node: Node) + fun > program(reaction: R, block: context(R) ActionableContext.() -> Unit = { }) { + context(reaction) { + ActionableContext.block() + } + node.addReaction(reaction) + } + + /** + * Creates a [Reaction] from an incarnation-specific program descriptor and registers it on the current [Node]. + * + * The [program] parameter is forwarded to [Incarnation.createReaction] and its meaning depends on the + * concrete incarnation in use. A `null` descriptor delegates the choice of the program to the incarnation. + * + * The created reaction uses the current [timeDistribution] context receiver, and is created within the + * current [environment], using the provided [randomGenerator], and targeting the current [node]. + * + * The optional [block] is applied as described in [program]([Reaction], block) before the reaction is added + * to the node. + * + * @param program the incarnation-specific reaction/program descriptor, possibly `null`. + * @param block an optional configuration block for actions and conditions. + */ + context( + incarnation: Incarnation, + randomGenerator: RandomGenerator, + environment: Environment, + node: Node, + timeDistribution: TimeDistribution + ) + fun program(program: String?, block: context(Reaction) ActionableContext.() -> Unit = { }) = program( + incarnation.createReaction(randomGenerator, environment, node, timeDistribution, program), + block, + ) +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableProvider.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableProvider.kt new file mode 100644 index 0000000000..4dc34d3fad --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableProvider.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import java.io.Serializable +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty + +/** + * Contract for DSL components that provide delegated, read-only variables. + * + * This interface integrates with Kotlin's delegated property mechanism by exposing [provideDelegate]. + * Implementations can intercept property delegation at declaration time to: + * - register the variable under the chosen property name; + * - return a [ReadOnlyProperty] that supplies the actual value at access time. + * + * The value type [V] must be [Serializable] to match Alchemist's requirements for scenario variables. + * + * @param V the type of value provided by the delegate. + */ +interface VariableProvider { + + /** + * Intercepts the delegation of a property and returns the [ReadOnlyProperty] that will supply its value. + * + * Implementations typically use [property.name] as the variable identifier and may use [thisRef] to + * associate the delegate with the owning instance, if needed. + * + * @param thisRef the object on which the property is delegated (or `null` for top-level properties). + * @param property the metadata of the delegated property. + * @return a read-only property delegate providing values of type [V]. + */ + operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): ReadOnlyProperty +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt index 6260052b43..5ac8d331ab 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt @@ -11,7 +11,7 @@ package it.unibo.alchemist.boundary.modelproviders import it.unibo.alchemist.boundary.AlchemistLoaderProvider import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.dsl.scripting.AlchemistScript +import it.unibo.alchemist.boundary.kotlindsl.AlchemistScript import java.io.InputStream import java.io.Reader import java.net.URL diff --git a/alchemist-loading/src/test/kotlin/DSL2.kt b/alchemist-loading/src/test/kotlin/DSL2.kt deleted file mode 100644 index 200e8dd7db..0000000000 --- a/alchemist-loading/src/test/kotlin/DSL2.kt +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package attempt - -import another.location.SimpleMonitor -import it.unibo.alchemist.boundary.DependentVariable -import it.unibo.alchemist.boundary.Exporter -import it.unibo.alchemist.boundary.Extractor -import it.unibo.alchemist.boundary.Launcher -import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.OutputMonitor -import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.exporters.CSVExporter -import it.unibo.alchemist.boundary.exportfilters.CommonFilters -import it.unibo.alchemist.boundary.extractors.Time -import it.unibo.alchemist.boundary.extractors.moleculeReader -import it.unibo.alchemist.boundary.launchers.DefaultLauncher -import it.unibo.alchemist.boundary.variables.GeometricVariable -import it.unibo.alchemist.boundary.variables.LinearVariable -import it.unibo.alchemist.core.Simulation -import it.unibo.alchemist.dsl.DslLoaderFunctions.makePerturbedGridForTesting -import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution -import it.unibo.alchemist.model.Action -import it.unibo.alchemist.model.Actionable -import it.unibo.alchemist.model.Condition -import it.unibo.alchemist.model.Deployment -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.GeoPosition -import it.unibo.alchemist.model.GlobalReaction -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Layer -import it.unibo.alchemist.model.LinkingRule -import it.unibo.alchemist.model.Molecule -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.NodeProperty -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.PositionBasedFilter -import it.unibo.alchemist.model.Reaction -import it.unibo.alchemist.model.TerminationPredicate -import it.unibo.alchemist.model.TimeDistribution -import it.unibo.alchemist.model.deployments.circle -import it.unibo.alchemist.model.deployments.grid -import it.unibo.alchemist.model.deployments.point -import it.unibo.alchemist.model.environments.Continuous2DEnvironment -import it.unibo.alchemist.model.environments.continuous2DEnvironment -import it.unibo.alchemist.model.incarnations.ProtelisIncarnation -import it.unibo.alchemist.model.incarnations.SAPEREIncarnation -import it.unibo.alchemist.model.layers.StepLayer -import it.unibo.alchemist.model.linkingrules.CombinedLinkingRule -import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance -import it.unibo.alchemist.model.linkingrules.NoLinks -import it.unibo.alchemist.model.maps.actions.reproduceGPSTrace -import it.unibo.alchemist.model.maps.deployments.FromGPSTrace -import it.unibo.alchemist.model.maps.environments.oSMEnvironment -import it.unibo.alchemist.model.positionfilters.Rectangle -import it.unibo.alchemist.model.positions.Euclidean2DPosition -import it.unibo.alchemist.model.reactions.event -import it.unibo.alchemist.model.terminators.AfterTime -import it.unibo.alchemist.model.terminators.StableForSteps -import it.unibo.alchemist.model.timedistributions.DiracComb -import it.unibo.alchemist.model.timedistributions.exponentialTime -import it.unibo.alchemist.model.timedistributions.weibullTime -import it.unibo.alchemist.model.times.DoubleTime -import it.unibo.alchemist.test.globalTestReaction -import java.io.Serializable -import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KProperty -import org.apache.commons.math3.random.MersenneTwister -import org.apache.commons.math3.random.RandomGenerator - -object ActionableContext { - context(actionable: Actionable) - fun action(action: Action) { - actionable.actions += action - } - context(actionable: Actionable) - fun condition(condition: Condition) { - actionable.conditions += condition - } -} - -object ContentContext { - - context(incarnation: Incarnation) - fun concentrationOf(origin: Any?): T = incarnation.createConcentration(origin) - - context(node: Node) - operator fun Pair.unaryMinus() { - node.setConcentration(first, second) - } - - context(incarnation: Incarnation, _: Node) - operator fun Molecule.unaryMinus() = -Pair(this, incarnation.createConcentration()) - - context(incarnation: Incarnation, _: Node) - operator fun String.unaryMinus() = -Pair(incarnation.createMolecule(this), incarnation.createConcentration()) - - context(incarnation: Incarnation, _: Node) - operator fun Pair.unaryMinus() = -Pair(incarnation.createMolecule(first), second) - -} - -interface TimeDistributionContext> { - - context(timeDistribution: TimeDistribution) - val timeDistribution: TimeDistribution get() = timeDistribution - - context(node: Node) - fun > program(reaction: R, block: context(R) ActionableContext.() -> Unit = { }) { - context(reaction) { - ActionableContext.block() - } - node.addReaction(reaction) - } - - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node, timeDistribution: TimeDistribution) - fun program(program: String?, block: context(Reaction) ActionableContext.() -> Unit = { }) = - program( - incarnation.createReaction(randomGenerator, environment, node, timeDistribution, program), - block - ) -} - -interface DeploymentContext> { - - val position: P - - fun > timeDistribution( - timeDistribution: TimeDistributionType, - block: context(TimeDistributionType) TimeDistributionContext.() -> Unit - ) { - context(timeDistribution) { - object : TimeDistributionContext { }.block() - } - } - - @Suppress("UNCHECKED_CAST") - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun withTimeDistribution( - parameter: Any? = null, - block: context(TimeDistribution) TimeDistributionContext.() -> Unit - ) = timeDistribution>( - parameter as? TimeDistribution ?: makeTimeDistribution(parameter), - block - ) - - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun program(program: String? = null, timeDistribution: Any? = null, block: context(Reaction) ActionableContext.() -> Unit = { }) = - withTimeDistribution(timeDistribution) { - program(program, block) - } - - context(_: Incarnation, _: Node) - fun contents(block: context(Incarnation) ContentContext.() -> Unit) { - ContentContext.block() - } - - context(node: Node) - fun nodeProperty(property: NodeProperty) { - node.addProperty(property) - } - - private companion object { - - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node) - fun > makeTimeDistribution(parameter: Any? = null): TimeDistribution = incarnation.createTimeDistribution( - randomGenerator, - environment, - node, - parameter, - ) - - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node, timeDistribution: TimeDistribution) - fun > makeReaction(descriptor: String?): Reaction = incarnation.createReaction( - randomGenerator, - environment, - node, - timeDistribution, - null, - ) - } -} - -object DeploymentsContext { - context(randomGenerator: RandomGenerator, environment: Environment) - fun > deploy(deployment: Deployment

, nodeFactory: (P) -> Node, block: context(RandomGenerator, Node) DeploymentContext.() -> Unit = {}) { - deployment.forEach { position -> - val node: Node = nodeFactory(position) - context(node) { - object : DeploymentContext { - override val position: P get() = position - }.block() - } - environment.addNode(node, position) - } - - } - context(incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment) - fun > deploy(deployment: Deployment

, nodeParameter: String? = null, block: context(RandomGenerator, Node) DeploymentContext.() -> Unit = {}) = - deploy(deployment, { incarnation.createNode(randomGenerator, environment, nodeParameter) }, block) -} - -object TerminatorsContext { - context(environment: Environment) - operator fun > TerminationPredicate.unaryMinus() = environment.addTerminator(this) -} - -interface EnvironmentContext> { - - fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) - - context(environment: Environment) - fun globalProgram(timeDistribution: TimeDistribution, globalReaction: GlobalReaction, block: context(GlobalReaction) ActionableContext.() -> Unit = {}) { - context(globalReaction) { - ActionableContext.block() - } - environment.addGlobalReaction(globalReaction) - } - - context(environment: Environment) - fun layer(molecule: Molecule, layer: Layer) = environment.addLayer(molecule, layer) - - context(incarnation: Incarnation, environment: Environment) - fun layer(molecule: String? = null, layer: Layer) = layer(incarnation.createMolecule(molecule), layer) - - context(environment: Environment) - fun networkModel(model: LinkingRule) = when(val currentRule = environment.linkingRule) { - is NoLinks -> environment.linkingRule = model - is CombinedLinkingRule -> environment.linkingRule = CombinedLinkingRule(currentRule.subRules + model) - else -> environment.linkingRule = CombinedLinkingRule(listOf(environment.linkingRule, model)) - } - - context(environment: Environment) - fun terminator(terminator: TerminationPredicate) = environment.addTerminator(terminator) -} - -interface ExporterContext> { - operator fun Extractor<*>.unaryMinus() -} - -interface VariableProvider { - operator fun provideDelegate( - thisRef: Any?, - property: KProperty<*>, - ): ReadOnlyProperty -} - -interface SimulationContext> { - fun > environment(environment: E, block: context(E) EnvironmentContext.() -> Unit) - fun exportWith(exporter: Exporter, block: ExporterContext.() -> Unit) - fun scenarioRandomGenerator(randomGenerator: RandomGenerator) - fun scenarioSeed(seed: Long) = scenarioRandomGenerator(MersenneTwister(seed)) - fun simulationRandomGenerator(randomGenerator: RandomGenerator) - fun simulationSeed(seed: Long) = simulationRandomGenerator(MersenneTwister(seed)) - fun monitor(monitor: OutputMonitor) - fun launcher(launcher: Launcher) - - fun variable(variable: Variable): VariableProvider -} - -operator fun PositionBasedFilter<*>.contains(position: Position<*>): Boolean = contains(position) - -context(_: Incarnation) -fun SimulationContext.environment(block: context(Continuous2DEnvironment) EnvironmentContext.() -> Unit) = - environment(continuous2DEnvironment(), block) - -fun , I : Incarnation> simulation(incarnation: I, block: context(I) SimulationContext.() -> Unit): Loader = object : Loader { - - override var constants: Map = emptyMap() - override val remoteDependencies: List get() = TODO("Not yet implemented") - override var launcher: Launcher = DefaultLauncher() - override val dependentVariables: Map> = emptyMap() - override var variables: Map> = emptyMap() - - @Suppress("UNCHECKED_CAST") - override fun > getWith(values: Map): Simulation = getWithTyped(values) as Simulation - - private fun getWithTyped(values: Map): Simulation { - var theEnvironment: Environment? = null - var simulationRandomGenerator: RandomGenerator = MersenneTwister(0) - var scenarioRandomGenerator: RandomGenerator = MersenneTwister(0) - context(incarnation) { - object : SimulationContext { - override fun > environment( - environment: E, - block: context(E) EnvironmentContext.() -> Unit - ) { - context(environment) { - object : EnvironmentContext { - override fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) { - TODO("Not yet implemented") - } - }.block() - } - theEnvironment = environment - } - - override fun exportWith( - exporter: Exporter, - block: ExporterContext.() -> Unit - ) { - TODO("Not yet implemented") - } - - override fun scenarioRandomGenerator(randomGenerator: RandomGenerator) { - checkSeedCanBeSet() - scenarioRandomGenerator = randomGenerator - } - - override fun simulationRandomGenerator(randomGenerator: RandomGenerator) { - checkSeedCanBeSet() - simulationRandomGenerator = randomGenerator - } - - override fun monitor(monitor: OutputMonitor) { - TODO("Not yet implemented") - } - - override fun launcher(launcher: Launcher) { - TODO("Not yet implemented") - } - - override fun variable(variable: Variable): VariableProvider { - TODO("Not yet implemented") - } - - fun checkSeedCanBeSet() { - check(theEnvironment == null) { - "Seeds must be set before the environment is defined, otherwise it might be used to create random elements in the environment with an unexpected seed" - } - } - }.block() - } - TODO() - } -} - -fun > simulationOnMap(incarnation: I, block: context(I) SimulationContext.() -> Unit) = simulation(incarnation, block) - -fun > simulation2D(incarnation: I, block: context(I) SimulationContext.() -> Unit) = simulation(incarnation, block) - -fun main() { - simulation(ProtelisIncarnation()) { - - } - simulation2D(SAPEREIncarnation()) { - val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) - val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) - - environment { - val mSize = -size - val sourceStart = mSize / 10.0 - val sourceSize = size / 5.0 - terminator(AfterTime(DoubleTime(1.0))) - networkModel(ConnectWithinDistance(0.5)) - deployments { - deploy(makePerturbedGridForTesting()) { - if (position in Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { - contents { - - "token, 0, []" - } - } - program( - "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}", - rate - ) - program("{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}") - } - } - } - } - simulation(ProtelisIncarnation()) { - exportWith(CSVExporter("test_export_interval", 4.0)) { - - Time() - - moleculeReader( - "default_module:default_program", - null, - CommonFilters.NOFILTER.filteringPolicy, - emptyList(), - ) - } - } - simulation2D(ProtelisIncarnation()) { - environment { - globalProgram(DiracComb(1.0), globalTestReaction(DiracComb(1.0))) - } - } - simulation2D(ProtelisIncarnation()) { - environment { - layer("A", StepLayer(2.0, 2.0, 100, 0)) - layer("B", StepLayer(-2.0, -2.0, 0, 100)) - deployments { - deploy( - grid( - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, - 0.1, - 0.1, - ), - ) { - contents { - - "a" - } - } - } - } - } - simulation2D(SAPEREIncarnation()) { - monitor(SimpleMonitor()) - } - simulationOnMap(SAPEREIncarnation()){ - environment(oSMEnvironment( "vcm.pbf", false)) { - terminator(StableForSteps(5, 100)) - deployments { - val gps = FromGPSTrace( - 7, - "gpsTrace", - true, - "AlignToSimulationTime", - ) - deploy(gps) { - withTimeDistribution(15) { - program(event()) { - action( - reproduceGPSTrace( - "gpsTrace", - true, - "AlignToSimulationTime", - ) - ) - } - } - } - } - } - } - simulation2D(SAPEREIncarnation()) { - environment { - networkModel(ConnectWithinDistance(0.5)) - deployments { - deploy(makePerturbedGridForTesting()) { - if (position in Rectangle(-0.5, -0.5, 1.0, 1.0)) { - contents { - - "token, 0, []" - } - } - timeDistribution(DiracComb(0.5)) { - program("{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}") - } - program("{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}") - } - } - } - } - simulation2D(ProtelisIncarnation()) { - environment { - deployments { - deploy(point(1.5, 0.5)) { - timeDistribution( - JaktaTimeDistribution( - sense = weibullTime(1.0, 1.0), - deliberate = DiracComb(0.1), - act = exponentialTime(1.0), - ) - ) { - program("1 + 1") - } - } - } - } - } - simulation2D(SAPEREIncarnation()) { - environment { - networkModel(ConnectWithinDistance(0.5)) - deployments { - val token = "token" - deploy(makePerturbedGridForTesting()) { - contents { - if (position in Rectangle(-0.5, -0.5, 1.0, 1.0)) { - - token - } - } - program( - "{token} --> {firing}", - timeDistribution = 1 - ) - program( "{firing} --> +{token}") - } - } - } - } - simulation2D(SAPEREIncarnation()) { - environment { - networkModel(ConnectWithinDistance(0.5)) - deployments { - val hello = "hello" - deploy(makePerturbedGridForTesting()) { - contents { - -hello - if (position in Rectangle(-1.0, -1.0, 2.0, 2.0)) { - - "token" - } - } - } - } - } - } - simulationOnMap(ProtelisIncarnation()) { - environment(oSMEnvironment( "vcm.pbf", false)) { - terminator(StableForSteps(5, 100)) - deployments { - deploy(FromGPSTrace(7, "gpsTrace", true, "AlignToSimulationTime")) { - program(timeDistribution = 15) { - action( - reproduceGPSTrace( - "gpsTrace", - true, - "AlignToSimulationTime", - ) - ) - } - } - } - } - } - simulation2D(SAPEREIncarnation()) { - environment { - deployments { - val p = point(0.0, 0.0) - deploy(p) - } - } - } - simulation2D(SAPEREIncarnation()) { - environment { - networkModel(ConnectWithinDistance(5.0)) - deployments { - deploy(point(0.0, 0.0)) - deploy(point(0.0, 1.0)) - } - } - } - simulation2D(SAPEREIncarnation()) { - simulationSeed(10L) - scenarioSeed(20L) - environment { - networkModel(ConnectWithinDistance(0.5)) - deployments { - deploy( - circle( - 10, - 0.0, - 0.0, - 10.0, - ), - ) - } - } - } - simulation2D(SAPEREIncarnation()) { - environment { - networkModel(ConnectWithinDistance(0.5)) - deployments { - val grid = grid( - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, - 0.25, - 0.0, - 0.0, - ) - deploy(grid) - } - } - } - simulation2D(SAPEREIncarnation()) { - environment { - networkModel(ConnectWithinDistance(0.5)) - deployments { - val hello = "hello" - deploy(makePerturbedGridForTesting()) { - contents { - -hello - } - } - } - } - } -} - -context(_: RandomGenerator, _: Environment<*, Euclidean2DPosition>) -fun makePerturbedGridForTesting() = grid( - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, - 0.25, - 0.1, - 0.1, -) - diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt deleted file mode 100644 index 68a4486cbf..0000000000 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/DslLoaderFunctions.kt +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.dsl - -import another.location.SimpleMonitor -import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.boundary.exporters.CSVExporter -import it.unibo.alchemist.boundary.exportfilters.CommonFilters -import it.unibo.alchemist.boundary.extractors.Time -import it.unibo.alchemist.boundary.extractors.moleculeReader -import it.unibo.alchemist.boundary.properties.testNodeProperty -import it.unibo.alchemist.boundary.variables.GeometricVariable -import it.unibo.alchemist.boundary.variables.LinearVariable -import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.GeoPosition -import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.actions.brownianMove -import it.unibo.alchemist.model.deployments.Circle -import it.unibo.alchemist.model.deployments.Grid -import it.unibo.alchemist.model.deployments.Point -import it.unibo.alchemist.model.deployments.circle -import it.unibo.alchemist.model.deployments.grid -import it.unibo.alchemist.model.deployments.point -import it.unibo.alchemist.model.deployments.polygon -import it.unibo.alchemist.model.environments.Continuous2DEnvironment -import it.unibo.alchemist.model.environments.Euclidean2DEnvironment -import it.unibo.alchemist.model.environments.continuous2DEnvironment -import it.unibo.alchemist.model.incarnations.ProtelisIncarnation -import it.unibo.alchemist.model.incarnations.SAPEREIncarnation -import it.unibo.alchemist.model.layers.StepLayer -import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance -import it.unibo.alchemist.model.maps.actions.ReproduceGPSTrace -import it.unibo.alchemist.model.maps.actions.reproduceGPSTrace -import it.unibo.alchemist.model.maps.deployments.FromGPSTrace -import it.unibo.alchemist.model.maps.environments.OSMEnvironment -import it.unibo.alchemist.model.maps.environments.oSMEnvironment -import it.unibo.alchemist.model.nodes.testNode -import it.unibo.alchemist.model.positionfilters.Rectangle -import it.unibo.alchemist.model.positions.Euclidean2DPosition -import it.unibo.alchemist.model.reactions.Event -import it.unibo.alchemist.model.sapere.ILsaMolecule -import it.unibo.alchemist.model.terminators.AfterTime -import it.unibo.alchemist.model.terminators.StableForSteps -import it.unibo.alchemist.model.timedistributions.DiracComb -import it.unibo.alchemist.model.timedistributions.ExponentialTime -import it.unibo.alchemist.model.timedistributions.WeibullTime -import it.unibo.alchemist.model.timedistributions.exponentialTime -import it.unibo.alchemist.model.timedistributions.weibullTime -import it.unibo.alchemist.model.times.DoubleTime -import it.unibo.alchemist.test.globalTestReaction -import org.apache.commons.math3.random.MersenneTwister -import org.apache.commons.math3.random.RandomGenerator - -object DslLoaderFunctions { - fun test01Nodes(): Loader = simulation(SAPEREIncarnation()) { - networkModel = ConnectWithinDistance(5.0) - deployments { - deploy(point(0.0, 0.0)) - deploy(point(0.0, 1.0)) - } - } - - fun test02ManyNodes(): Loader { - return simulation(SAPEREIncarnation()) { - seeds { - simulation(10L) - scenario(20L) - } - networkModel = ConnectWithinDistance(0.5) - deployments { - deploy( - circle( - 10, - 0.0, - 0.0, - 10.0, - ), - ) - } - } - } - fun test03Grid(): Loader { - return simulation(SAPEREIncarnation()) { - networkModel = ConnectWithinDistance(0.5) - deployments { - val grid = grid( - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, - 0.25, - 0.0, - 0.0, - ) - deploy(grid) - } - } - } - context(_: RandomGenerator, _: Environment<*, Euclidean2DPosition>) - fun makePerturbedGridForTesting() = grid( - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, - 0.25, - 0.1, - 0.1, - ) - fun test05Content(): Loader { - return simulation(SAPEREIncarnation()) { - networkModel = ConnectWithinDistance(0.5) - deployments { - val hello = "hello" - deploy(makePerturbedGridForTesting()) - { - all { - molecule = hello - } - } - } - } - } - fun test06ContentFiltered(): Loader { - return simulation(SAPEREIncarnation()) { - networkModel = ConnectWithinDistance(0.5) - deployments { - val hello = "hello" - deploy(makePerturbedGridForTesting()) { - all { - molecule = hello - } - inside(Rectangle(-1.0, -1.0, 2.0, 2.0)) { - molecule = "token" - } - } - } - } - } - - fun test07Programs(): Loader { - return simulation(SAPEREIncarnation()) { - networkModel = ConnectWithinDistance(0.5) - deployments { - val token = "token" - deploy(makePerturbedGridForTesting()) { - inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { - molecule = token - } - programs { - all { - timeDistribution("1") - program = "{token} --> {firing}" - } - all { - program = "{firing} --> +{token}" - } - } - } - } - } - } - fun test08ProtelisPrograms(): Loader = simulation(ProtelisIncarnation()) { - deployments { - deploy(point(1.5, 0.5)) { - programs { - all { - timeDistribution = JaktaTimeDistribution( - sense = weibullTime( - 1.0, - 1.0, - ), - deliberate = DiracComb(0.1), - act = exponentialTime(1.0), - ) - program = "1 + 1" - } - } - } - } - } - fun test09TimeDistribution(): Loader { - return simulation(SAPEREIncarnation()) { - networkModel = ConnectWithinDistance(0.5) - deployments { - deploy(makePerturbedGridForTesting()) { - inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { - molecule = "token, 0, []" - } - programs { - all { - timeDistribution = DiracComb(0.5) - program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" - } - all { - program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" - } - } - } - } - } - } - fun test10Environment(): Loader { - val incarnation = SAPEREIncarnation() - return simulation(incarnation) { - environment { oSMEnvironment( "vcm.pbf", false) } - terminators { - +StableForSteps(5, 100) - } - deployments { - val gps = FromGPSTrace( - 7, - "gpsTrace", - true, - "AlignToSimulationTime", - ) - deploy(gps) { - programs { - all { - timeDistribution("15") - reaction = Event(node, timeDistribution) - addAction { - reproduceGPSTrace( - "gpsTrace", - true, - "AlignToSimulationTime", - ) - } - } - } - } - } - } - } - fun test11monitors(): Loader { - return simulation(SAPEREIncarnation()) { - monitors { - +SimpleMonitor, Euclidean2DPosition>() - } - } - } - fun test12Layers(): Loader { - val incarnation = ProtelisIncarnation() - return simulation(incarnation) { - layer { - molecule = "A" - layer = StepLayer( - 2.0, - 2.0, - 100, - 0, - ) - } - layer { - molecule = "B" - layer = StepLayer( - -2.0, - -2.0, - 0, - 100, - ) - } - deployments { - deploy( - grid( - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, - 0.1, - 0.1, - ), - ) { - all { - molecule = "a" - } - } - } - } - } - fun test13GlobalReaction(): Loader = simulation(ProtelisIncarnation()) { - programs { - +globalTestReaction(DiracComb(1.0)) - } - } - fun test14Exporters(): Loader = simulation(ProtelisIncarnation()) { - exporter { - type = CSVExporter( - "test_export_interval", - 4.0, - ) - data( - Time(), - moleculeReader( - "default_module:default_program", - null, - CommonFilters.NOFILTER.filteringPolicy, - emptyList(), - ), - ) - } - } - fun test15Variables(): Loader = simulation(SAPEREIncarnation()) { - val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) - val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) - - val mSize by variable { -size } - val sourceStart by variable { mSize / 10.0 } - val sourceSize by variable { size / 5.0 } - terminators { +AfterTime, Euclidean2DPosition>(DoubleTime(1.0)) } - networkModel = ConnectWithinDistance(0.5) - deployments { - deploy(makePerturbedGridForTesting()) { - inside(Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { - molecule = "token, 0, []" - } - programs { - all { - timeDistribution(rate.toString()) - program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" - } - all { - program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" - } - } - } - } - } - - fun test16ProgramsFilters(): Loader { - return simulation(SAPEREIncarnation()) { - networkModel = ConnectWithinDistance(0.5) - deployments { - val token = "token" - deploy(makePerturbedGridForTesting()) { - inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { - molecule = token - } - programs { - inside(Rectangle(-0.5, -0.5, 1.0, 1.0)) { - timeDistribution("1") - program = "{token} --> {firing}" - } - all { - program = "{firing} --> +{token}" - } - } - } - } - } - } - fun test17CustomNodes(): Loader { - return simulation(SAPEREIncarnation()) { - deployments { - deploy( - circle( - 10, - 0.0, - 0.0, - 5.0, - ), - nodeFactory = { testNode() }, - ) { - } - } - } - } - fun test18NodeProperties(): Loader { - val incarnation = SAPEREIncarnation() - val environment = Continuous2DEnvironment(incarnation) - return simulation(incarnation, { environment }) { - deployments { - deploy( - circle( - 1000, - 0.0, - 0.0, - 15.0, - ), - ) { - properties { - val filter = Rectangle(-3.0, -3.0, 2.0, 2.0) - // same - inside(filter) { - +testNodeProperty("a") - } - inside(Rectangle(3.0, 3.0, 2.0, 2.0)) { - +testNodeProperty("b") - } - } - } - } - } - } - fun test20Actions(): Loader = simulation(SAPEREIncarnation(), { - oSMEnvironment() - }) { - networkModel = ConnectWithinDistance(1000.0) - deployments { - val lagoon = listOf( - Pair(45.2038121, 12.2504425), - Pair(45.2207426, 12.2641754), - Pair(45.2381516, 12.2806549), - Pair(45.2570053, 12.2895813), - Pair(45.276336, 12.2957611), - Pair(45.3029049, 12.2991943), - Pair(45.3212544, 12.3046875), - Pair(45.331875, 12.3040009), - Pair(45.3453893, 12.3040009), - Pair(45.3502151, 12.3156738), - Pair(45.3622776, 12.3232269), - Pair(45.3719259, 12.3300934), - Pair(45.3830193, 12.3348999), - Pair(45.395557, 12.3445129), - Pair(45.3998964, 12.3300934), - Pair(45.4018249, 12.3136139), - Pair(45.4105023, 12.3122406), - Pair(45.4167685, 12.311554), - Pair(45.4278531, 12.3012543), - Pair(45.4408627, 12.2902679), - Pair(45.4355628, 12.2772217), - Pair(45.4206242, 12.2703552), - Pair(45.3994143, 12.2744751), - Pair(45.3738553, 12.2676086), - Pair(45.3579354, 12.2614288), - Pair(45.3429763, 12.2497559), - Pair(45.3198059, 12.2408295), - Pair(45.2975921, 12.2346497), - Pair(45.2802014, 12.2408295), - Pair(45.257972, 12.233963), - Pair(45.2038121, 12.2504425), - ) - deploy(polygon(500, lagoon)) { - programs { - all { - timeDistribution("10") - reaction = Event(node, timeDistribution) - addAction { - brownianMove( - 0.0005, - ) - } - } - } - } - } - } -} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt index 735b4c71c0..f4472d6679 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt @@ -63,7 +63,7 @@ object RuntimeComparisonHelper { * Small timing differences are expected even with time-based terminators due to thread * scheduling and the terminator being checked after each step completes. */ - fun > compareLoaders( + fun > compareLoaders( dslLoader: Loader, yamlLoader: Loader, steps: Long? = null, @@ -120,7 +120,7 @@ object RuntimeComparisonHelper { stableForSteps: Pair?, ): Boolean = effectiveSteps > 0 || targetTime != null || stableForSteps != null - private fun > addTerminators( + private fun > addTerminators( dslSimulation: Simulation, yamlSimulation: Simulation, steps: Long?, @@ -220,13 +220,12 @@ object RuntimeComparisonHelper { * Terminates when environment (positions + node contents) remains unchanged * for checkInterval * equalIntervals steps. */ - private fun > addStableTerminator( + private fun > addStableTerminator( simulation: Simulation, checkInterval: Long, equalIntervals: Long, ) { - @Suppress("UNCHECKED_CAST") - val terminator = StableForSteps(checkInterval, equalIntervals) as + val terminator = StableForSteps(checkInterval, equalIntervals) as TerminationPredicate simulation.environment.addTerminator(terminator) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt index cd5b569e85..afa7bcc84c 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt @@ -13,100 +13,101 @@ import org.junit.jupiter.api.Test class SimulationsComparisons { - @Test - fun test01() { - { DslLoaderFunctions.test01Nodes() }.shouldEqual("dsl/yml/01-nodes.yml") - } - - @Test - fun test02() { - { DslLoaderFunctions.test02ManyNodes() }.shouldEqual("dsl/yml/02-manynodes.yml") - } - - @Test - fun test03() { - { DslLoaderFunctions.test03Grid() }.shouldEqual("dsl/yml/03-grid.yml") - } - - @Test - fun test05() { - { DslLoaderFunctions.test05Content() }.shouldEqual("dsl/yml/05-content.yml") - } - - @Test - fun test06() { - { DslLoaderFunctions.test06ContentFiltered() }.shouldEqual("dsl/yml/06-filters.yml") - } - - @Test - fun test07() { - { DslLoaderFunctions.test07Programs() }.shouldEqual("dsl/yml/07-program.yml") - } - - @Test - fun test08() { - DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/yml/08-protelisprogram.yml") - } - - @Test - fun test09() { - { DslLoaderFunctions.test09TimeDistribution() }.shouldEqual("dsl/yml/09-timedistribution.yml") - } - - @Test - fun test10() { - { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/yml/10-environment.yml") - } - - @Test - fun test11() { - { DslLoaderFunctions.test11monitors() }.shouldEqual("dsl/yml/11-monitors.yml") - } - - @Test - fun > test12() { - { DslLoaderFunctions.test12Layers() }.shouldEqual("dsl/yml/12-layers.yml") - } - - @Test - fun > test13() { - { DslLoaderFunctions.test13GlobalReaction() }.shouldEqual("dsl/yml/13-globalreaction.yml") - } - - @Test - fun > test14() { - { DslLoaderFunctions.test14Exporters() }.shouldEqual("dsl/yml/14-exporters.yml") - } - - @Test - fun test15() { - { DslLoaderFunctions.test15Variables() }.shouldEqual("dsl/yml/15-variables.yml") - } - - @Test - fun test16() { - { DslLoaderFunctions.test16ProgramsFilters() } - .shouldEqual( - "dsl/yml/16-programsfilters.yml", - targetTime = 10.0, - ) - } - - @Test - fun test17() { - { DslLoaderFunctions.test17CustomNodes() }.shouldEqual("dsl/yml/17-customnodes.yml") - } - - @Test - fun test18() { - { DslLoaderFunctions.test18NodeProperties() }.shouldEqual("dsl/yml/18-properties.yml") - } - - @Test - fun test20() { - { DslLoaderFunctions.test20Actions() }.shouldEqual( - "dsl/yml/20-move.yml", - targetTime = 10.0, - ) - } + // TODO: rewrite +// @Test +// fun test01() { +// { DslLoaderFunctions.test01Nodes() }.shouldEqual("dsl/yml/01-nodes.yml") +// } +// +// @Test +// fun test02() { +// { DslLoaderFunctions.test02ManyNodes() }.shouldEqual("dsl/yml/02-manynodes.yml") +// } +// +// @Test +// fun test03() { +// { DslLoaderFunctions.test03Grid() }.shouldEqual("dsl/yml/03-grid.yml") +// } +// +// @Test +// fun test05() { +// { DslLoaderFunctions.test05Content() }.shouldEqual("dsl/yml/05-content.yml") +// } +// +// @Test +// fun test06() { +// { DslLoaderFunctions.test06ContentFiltered() }.shouldEqual("dsl/yml/06-filters.yml") +// } +// +// @Test +// fun test07() { +// { DslLoaderFunctions.test07Programs() }.shouldEqual("dsl/yml/07-program.yml") +// } +// +// @Test +// fun test08() { +// DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/yml/08-protelisprogram.yml") +// } +// +// @Test +// fun test09() { +// { DslLoaderFunctions.test09TimeDistribution() }.shouldEqual("dsl/yml/09-timedistribution.yml") +// } +// +// @Test +// fun test10() { +// { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/yml/10-environment.yml") +// } +// +// @Test +// fun test11() { +// { DslLoaderFunctions.test11monitors() }.shouldEqual("dsl/yml/11-monitors.yml") +// } +// +// @Test +// fun > test12() { +// { DslLoaderFunctions.test12Layers() }.shouldEqual("dsl/yml/12-layers.yml") +// } +// +// @Test +// fun > test13() { +// { DslLoaderFunctions.test13GlobalReaction() }.shouldEqual("dsl/yml/13-globalreaction.yml") +// } +// +// @Test +// fun > test14() { +// { DslLoaderFunctions.test14Exporters() }.shouldEqual("dsl/yml/14-exporters.yml") +// } +// +// @Test +// fun test15() { +// { DslLoaderFunctions.test15Variables() }.shouldEqual("dsl/yml/15-variables.yml") +// } +// +// @Test +// fun test16() { +// { DslLoaderFunctions.test16ProgramsFilters() } +// .shouldEqual( +// "dsl/yml/16-programsfilters.yml", +// targetTime = 10.0, +// ) +// } +// +// @Test +// fun test17() { +// { DslLoaderFunctions.test17CustomNodes() }.shouldEqual("dsl/yml/17-customnodes.yml") +// } +// +// @Test +// fun test18() { +// { DslLoaderFunctions.test18NodeProperties() }.shouldEqual("dsl/yml/18-properties.yml") +// } +// +// @Test +// fun test20() { +// { DslLoaderFunctions.test20Actions() }.shouldEqual( +// "dsl/yml/20-move.yml", +// targetTime = 10.0, +// ) +// } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt index 537fcc0791..e97029b049 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt @@ -32,7 +32,7 @@ object TestComparators { * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). * Exactly one of steps, targetTime, or stableForSteps must be provided. */ - fun > compare( + fun > compare( dslLoader: () -> Loader, yamlResource: String, includeRuntime: Boolean = false, @@ -69,7 +69,7 @@ object TestComparators { * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). * Exactly one of steps, targetTime, or stableForSteps must be provided. */ - fun > compare( + fun > compare( dslCode: String, yamlResource: String, includeRuntime: Boolean = false, @@ -95,7 +95,7 @@ object TestComparators { * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). * Exactly one of steps, targetTime, or stableForSteps must be provided. */ - fun > compare( + fun > compare( dslLoader: Loader, yamlLoader: Loader, includeRuntime: Boolean = false, diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt index bc80b7524f..3637893e42 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -9,8 +9,9 @@ package it.unibo.alchemist.dsl -import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.boundary.kotlindsl.environment +import it.unibo.alchemist.boundary.kotlindsl.simulation +import it.unibo.alchemist.boundary.kotlindsl.simulation2D import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.sapere.molecules.LsaMolecule @@ -20,12 +21,13 @@ class TestContents { @Test fun testAll() { - val loader = simulation(SAPEREIncarnation()) { - deployments { - deploy(point(0.0, 0.0)) { - all { - molecule = "test" - concentration = listOf(LsaMolecule("1")) + val loader = simulation2D(SAPEREIncarnation()) { + environment { + deployments { + deploy(point(0.0, 0.0)) { + contents { + - "test" to listOf(LsaMolecule("1")) + } } } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDSLLoading.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDSLLoading.kt new file mode 100644 index 0000000000..33dbfe7509 --- /dev/null +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDSLLoading.kt @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.dsl + +import another.location.SimpleMonitor +import it.unibo.alchemist.boundary.exporters.CSVExporter +import it.unibo.alchemist.boundary.exportfilters.CommonFilters +import it.unibo.alchemist.boundary.extractors.Time +import it.unibo.alchemist.boundary.extractors.moleculeReader +import it.unibo.alchemist.boundary.kotlindsl.ActionableContext +import it.unibo.alchemist.boundary.kotlindsl.contains +import it.unibo.alchemist.boundary.kotlindsl.environment +import it.unibo.alchemist.boundary.kotlindsl.simulation +import it.unibo.alchemist.boundary.kotlindsl.simulation2D +import it.unibo.alchemist.boundary.kotlindsl.simulationOnMap +import it.unibo.alchemist.boundary.variables.GeometricVariable +import it.unibo.alchemist.boundary.variables.LinearVariable +import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.deployments.circle +import it.unibo.alchemist.model.deployments.grid +import it.unibo.alchemist.model.deployments.point +import it.unibo.alchemist.model.incarnations.ProtelisIncarnation +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation +import it.unibo.alchemist.model.layers.StepLayer +import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance +import it.unibo.alchemist.model.maps.actions.reproduceGPSTrace +import it.unibo.alchemist.model.maps.deployments.FromGPSTrace +import it.unibo.alchemist.model.maps.environments.oSMEnvironment +import it.unibo.alchemist.model.positionfilters.Rectangle +import it.unibo.alchemist.model.positions.Euclidean2DPosition +import it.unibo.alchemist.model.reactions.event +import it.unibo.alchemist.model.terminators.AfterTime +import it.unibo.alchemist.model.terminators.StableForSteps +import it.unibo.alchemist.model.timedistributions.DiracComb +import it.unibo.alchemist.model.timedistributions.exponentialTime +import it.unibo.alchemist.model.timedistributions.weibullTime +import it.unibo.alchemist.model.times.DoubleTime +import it.unibo.alchemist.test.globalTestReaction +import org.apache.commons.math3.random.RandomGenerator +import org.junit.jupiter.api.Test + +class TestDSLLoading { + + @Test + fun `verify that the base syntax of the Kotlin DSL compiles and builds without throwing exceptions`() { + simulation(ProtelisIncarnation()) { + environment { } + }.let { it.launcher.launch(it) } + simulation2D(SAPEREIncarnation()) { + val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) + val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) + environment { + val mSize = -size + val sourceStart = mSize / 10.0 + val sourceSize = size / 5.0 + terminator(AfterTime(DoubleTime(1.0))) + networkModel(ConnectWithinDistance(0.5)) + deployments { + deploy(makePerturbedGridForTesting()) { + if (position in Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { + contents { + -"token, 0, []" + } + } + program( + "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}", + rate, + ) + program("{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}") + } + } + } + } + simulation(ProtelisIncarnation()) { + exportWith(CSVExporter("test_export_interval", 4.0)) { + -Time() + -moleculeReader( + "default_module:default_program", + null, + CommonFilters.NOFILTER.filteringPolicy, + emptyList(), + ) + } + } + simulation2D(ProtelisIncarnation()) { + environment { + globalProgram(DiracComb(1.0), globalTestReaction(DiracComb(1.0))) + } + } + simulation2D(ProtelisIncarnation()) { + environment { + layer("A", StepLayer(2.0, 2.0, 100, 0)) + layer("B", StepLayer(-2.0, -2.0, 0, 100)) + deployments { + deploy( + grid( + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.1, + 0.1, + ), + ) { + contents { + -"a" + } + } + } + } + } + simulation2D(SAPEREIncarnation()) { + monitor(SimpleMonitor()) + } + simulationOnMap(SAPEREIncarnation()) { + environment(oSMEnvironment("vcm.pbf", false)) { + terminator(StableForSteps(5, 100)) + deployments { + val gps = FromGPSTrace( + 7, + "gpsTrace", + true, + "AlignToSimulationTime", + ) + deploy(gps) { + withTimeDistribution(15) { + program(event()) { + ActionableContext.action( + reproduceGPSTrace( + "gpsTrace", + true, + "AlignToSimulationTime", + ), + ) + } + } + } + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + deploy(makePerturbedGridForTesting()) { + if (position in Rectangle(-0.5, -0.5, 1.0, 1.0)) { + contents { + -"token, 0, []" + } + } + timeDistribution(DiracComb(0.5)) { + program("{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}") + } + program("{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}") + } + } + } + } + simulation2D(ProtelisIncarnation()) { + environment { + deployments { + deploy(point(1.5, 0.5)) { + timeDistribution( + JaktaTimeDistribution( + sense = weibullTime(1.0, 1.0), + deliberate = DiracComb(0.1), + act = exponentialTime(1.0), + ), + ) { + program("1 + 1") + } + } + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + val token = "token" + deploy(makePerturbedGridForTesting()) { + contents { + if (position in Rectangle(-0.5, -0.5, 1.0, 1.0)) { + -token + } + } + program( + "{token} --> {firing}", + timeDistribution = 1, + ) + program("{firing} --> +{token}") + } + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + val hello = "hello" + deploy(makePerturbedGridForTesting()) { + contents { + -hello + if (position in Rectangle(-1.0, -1.0, 2.0, 2.0)) { + -"token" + } + } + } + } + } + } + simulationOnMap(ProtelisIncarnation()) { + environment(oSMEnvironment("vcm.pbf", false)) { + terminator(StableForSteps(5, 100)) + deployments { + deploy(FromGPSTrace(7, "gpsTrace", true, "AlignToSimulationTime")) { + program(timeDistribution = 15) { + action( + reproduceGPSTrace( + "gpsTrace", + true, + "AlignToSimulationTime", + ), + ) + } + } + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + deployments { + val p = point(0.0, 0.0) + deploy(p) + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(5.0)) + deployments { + deploy(point(0.0, 0.0)) + deploy(point(0.0, 1.0)) + } + } + } + simulation2D(SAPEREIncarnation()) { + simulationSeed(10L) + scenarioSeed(20L) + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + deploy( + circle( + 10, + 0.0, + 0.0, + 10.0, + ), + ) + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + val grid = grid( + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.25, + 0.0, + 0.0, + ) + deploy(grid) + } + } + } + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(0.5)) + deployments { + val hello = "hello" + deploy(makePerturbedGridForTesting()) { + contents { + -hello + } + } + } + } + } + } + companion object { + context(_: RandomGenerator, _: Environment<*, Euclidean2DPosition>) + fun makePerturbedGridForTesting() = grid( + -5.0, + -5.0, + 5.0, + 5.0, + 0.25, + 0.25, + 0.1, + 0.1, + ) + } +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index fc9840aaf1..f090617fc3 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -9,9 +9,8 @@ package it.unibo.alchemist.dsl -import it.unibo.alchemist.boundary.dsl.Dsl.simulation -import it.unibo.alchemist.model.deployments.Grid -import it.unibo.alchemist.model.deployments.Point +import it.unibo.alchemist.boundary.kotlindsl.environment +import it.unibo.alchemist.boundary.kotlindsl.simulation2D import it.unibo.alchemist.model.deployments.grid import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.incarnations.SAPEREIncarnation @@ -21,10 +20,12 @@ class TestDeployments { @Test fun testDeployments() { - val loader = simulation(SAPEREIncarnation()) { - deployments { - val p = point(0.0, 0.0) - deploy(p) + val loader = simulation2D(SAPEREIncarnation()) { + environment { + deployments { + val p = point(0.0, 0.0) + deploy(p) + } } } @@ -33,12 +34,13 @@ class TestDeployments { @Test fun testMultipleDeployments() { - val loader = simulation(SAPEREIncarnation()) { - deployments { + val loader = simulation2D(SAPEREIncarnation()) { + environment { + deployments { val point = point(0.0, 0.0) deploy(point) deploy(point(1.0, 1.0)) - } + }} } loader.launch(loader.launcher) @@ -46,8 +48,9 @@ class TestDeployments { @Test fun testGridDeployment() { - val loader = simulation(SAPEREIncarnation()) { - deployments { + val loader = simulation2D(SAPEREIncarnation()) { + environment { + deployments { val grid = grid( 1.0, 1.0, @@ -58,7 +61,7 @@ class TestDeployments { ) deploy(grid) } - } + }} loader.launch(loader.launcher) } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt index 740f98ae36..2d691ada08 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt @@ -9,7 +9,8 @@ package it.unibo.alchemist.dsl -import it.unibo.alchemist.boundary.dsl.Dsl.simulation +import it.unibo.alchemist.boundary.kotlindsl.environment +import it.unibo.alchemist.boundary.kotlindsl.simulation2D import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import org.junit.jupiter.api.Test @@ -18,14 +19,16 @@ class TestSimulations { @Test fun testIncarnation() { - val loader = simulation(SAPEREIncarnation()) { } + val loader = simulation2D(SAPEREIncarnation()) { } loader.launch(loader.launcher) } @Test fun testLinkingRule() { - val loader = simulation(SAPEREIncarnation()) { - networkModel = ConnectWithinDistance(5.0) + val loader = simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(5.0)) + } } loader.launch(loader.launcher) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt index da4ea6fca7..bf385fea3e 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -12,8 +12,10 @@ package it.unibo.alchemist.dsl import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.booleans.shouldBeTrue import io.kotest.matchers.doubles.shouldBeExactly +import io.kotest.matchers.maps.shouldNotBeEmpty import io.kotest.matchers.shouldBe -import it.unibo.alchemist.boundary.dsl.Dsl.simulation +import it.unibo.alchemist.boundary.kotlindsl.environment +import it.unibo.alchemist.boundary.kotlindsl.simulation2D import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.model.Position @@ -21,39 +23,42 @@ import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.incarnations.ProtelisIncarnation import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.molecules.SimpleMolecule +import it.unibo.alchemist.model.positions.Euclidean2DPosition import it.unibo.alchemist.model.sapere.molecules.LsaMolecule import org.junit.jupiter.api.Test class TestVariables { @Test fun

> testDefaultValue() { - simulation(SAPEREIncarnation()) { + val loader = simulation2D(SAPEREIncarnation()) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) - - runLater { + environment { println("Checking variable") rate.shouldBeExactly(5.0) - this.variablesContext.variables.containsKey("rate").shouldBeTrue() } - }.getDefault, P>() // needed to build the simulation + } + loader.variables.shouldNotBeEmpty() } @Test fun

> testOverrideValue() { - val loader = simulation(SAPEREIncarnation()) { + var assertion = { rate: Double -> rate.shouldBeExactly(5.0) } + val loader = simulation2D(SAPEREIncarnation()) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) - deployments { - rate.shouldBeExactly(20.0) - variablesContext.variables.containsKey("rate").shouldBeTrue() + environment { + deployments { + assertion(rate) + } } } + loader.variables.containsKey("rate").shouldBeTrue() + assertion = { it.shouldBeExactly(20.0) } loader.getWith, P>(mapOf("rate" to 20.0)) } @Test - @Suppress("NoNameShadowing") fun

> testDoubleDeclaration() { - simulation(SAPEREIncarnation()) { + simulation2D(SAPEREIncarnation()) { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) println("First declaration of rate: $rate") shouldThrow { @@ -64,35 +69,28 @@ class TestVariables { } @Test - fun

> testDependendVariable() { - val loader = simulation(ProtelisIncarnation()) { + fun testDependendVariable() { + val loader = simulation2D(ProtelisIncarnation()) { val geometricVariable: Double by variable(GeometricVariable(10.0, 1.0, 1000.0, 4)) val linearVariable: Double by variable(LinearVariable(1.0, 1.0, 2.0, 3.0)) - val mSize by variable { -linearVariable } - val sourceStart by variable { mSize / geometricVariable } - val sourceSize by variable { linearVariable / 5.0 } - + val mSize = -linearVariable + val sourceStart = mSize / geometricVariable + val sourceSize = linearVariable / 5.0 +environment { deployments { deploy(point(0.0, 0.0)) { - all { - molecule = "mSize" - concentration = mSize - } - all { - molecule = "sourceStart" - concentration = sourceStart - } - all { - molecule = "sourceSize" - concentration = sourceSize + contents { + - "mSize" to mSize + - "sourceStart" to sourceStart + - "sourceSize" to sourceSize } } - } + }} } loader.variables.size shouldBe 2 loader.dependentVariables.size shouldBe 0 - loader.getWith, P>(mapOf("linearVariable" to 10.0)).apply { + loader.getWith(mapOf("linearVariable" to 10.0)).apply { environment.nodes.size shouldBe 1 val node = environment.nodes.single() node.getConcentration(SimpleMolecule("mSize")) shouldBe -10.0 diff --git a/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/reactions/PhysicsUpdate.kt b/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/reactions/PhysicsUpdate.kt index 8b4234b8e6..b306fdf1b7 100644 --- a/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/reactions/PhysicsUpdate.kt +++ b/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/reactions/PhysicsUpdate.kt @@ -31,12 +31,12 @@ class PhysicsUpdate( * The environment to update. */ val environment: Dynamics2DEnvironment, - override val timeDistribution: TimeDistribution, + override val timeDistribution: TimeDistribution = DiracComb(DEFAULT_RATE), ) : GlobalReaction { constructor( environment: Dynamics2DEnvironment, - updateRate: Double = 30.0, + updateRate: Double, ) : this(environment, DiracComb(updateRate)) override val outboundDependencies: ListSet = ListSet.of(PhysicsDependency) @@ -65,4 +65,8 @@ class PhysicsUpdate( override fun update(currentTime: Time, hasBeenExecuted: Boolean, environment: Environment) = Unit override fun initializationComplete(atTime: Time, environment: Environment) = Unit + + private companion object { + const val DEFAULT_RATE = 30.0 + } } From f0eaf9302cdbc6352251ab59929d729580e5a249 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 9 Feb 2026 20:55:02 +0100 Subject: [PATCH 162/196] style: remove unnecessary whitespace in TerminatorsContext.kt --- .../it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt index f8db8a7cd2..91f2e7f98c 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt @@ -34,4 +34,3 @@ object TerminatorsContext { context(environment: Environment) operator fun > TerminationPredicate.unaryMinus() = environment.addTerminator(this) } - From 57d4c68382a5c74314108be529ccaa832f039c09 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 9 Feb 2026 20:55:41 +0100 Subject: [PATCH 163/196] style: reorder imports in SimulationContext.kt --- .../unibo/alchemist/boundary/kotlindsl/SimulationContext.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt index d23b45c928..a517635e78 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt @@ -15,10 +15,10 @@ import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.Variable import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position -import org.apache.commons.math3.random.MersenneTwister -import org.apache.commons.math3.random.RandomGenerator import java.io.Serializable import kotlin.properties.ReadOnlyProperty +import org.apache.commons.math3.random.MersenneTwister +import org.apache.commons.math3.random.RandomGenerator /** * Top-level DSL scope for defining a simulation scenario. From 2052a1291b33499123eda67ab408ab80c58f5752 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 9 Feb 2026 20:58:23 +0100 Subject: [PATCH 164/196] fix(incarnation-scafi): remove unused time parameter from action and condition creation --- .../model/incarnations/ScafiIncarnation.scala | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala index 766568214c..e5bddf6ee9 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala @@ -8,15 +8,15 @@ */ package it.unibo.alchemist.model.incarnations +import it.unibo.alchemist.model._ import it.unibo.alchemist.model.molecules.SimpleMolecule import it.unibo.alchemist.model.nodes.GenericNode import it.unibo.alchemist.model.reactions.{ChemicalReaction, Event} -import it.unibo.alchemist.model.timedistributions.{DiracComb, ExponentialTime} -import it.unibo.alchemist.model.times.DoubleTime -import it.unibo.alchemist.model._ import it.unibo.alchemist.model.scafi.actions.{RunScafiProgram, SendScafiMessage} import it.unibo.alchemist.model.scafi.conditions.ScafiComputationalRoundComplete import it.unibo.alchemist.model.scafi.properties.ScafiDevice +import it.unibo.alchemist.model.timedistributions.{DiracComb, ExponentialTime} +import it.unibo.alchemist.model.times.DoubleTime import it.unibo.alchemist.scala.ScalaInterpreter import org.apache.commons.math3.random.RandomGenerator @@ -48,7 +48,6 @@ sealed class ScafiIncarnation[T, P <: Position[P]] extends Incarnation[T, P] { randomGenerator: RandomGenerator, environment: Environment[T, P], node: Node[T], - time: TimeDistribution[T], reaction: Actionable[T], param: Any ): Action[T] = runInScafiDeviceContext[T, Action[T]]( @@ -106,7 +105,6 @@ sealed class ScafiIncarnation[T, P <: Position[P]] extends Incarnation[T, P] { randomGenerator: RandomGenerator, environment: Environment[T, P], node: Node[T], - time: TimeDistribution[T], reaction: Actionable[T], parameters: Any ): Condition[T] = runInScafiDeviceContext[T, Condition[T]]( @@ -168,12 +166,12 @@ sealed class ScafiIncarnation[T, P <: Position[P]] extends Incarnation[T, P] { } if (parameters != null) { result.setActions( - ListBuffer[Action[T]](createAction(randomGenerator, environment, node, time, result, parameterString)).asJava + ListBuffer[Action[T]](createAction(randomGenerator, environment, node, result, parameterString)).asJava ) } if (isSend) { result.setConditions( - ListBuffer[Condition[T]](createCondition(randomGenerator, environment, node, time, result, null)).asJava + ListBuffer[Condition[T]](createCondition(randomGenerator, environment, node, result, null)).asJava ) } result From 41fa44d708fc664b8bdfa2fff03041f4a23a7e3e Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 9 Feb 2026 20:59:51 +0100 Subject: [PATCH 165/196] style: apply KTLintFormat to AlchemistKotlinDSL.kt --- .../alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt index b34d4e3b5f..93c2bf8529 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt @@ -40,7 +40,7 @@ import org.danilopianini.util.SpatialIndex import org.slf4j.LoggerFactory @Suppress("UNCHECKED_CAST") -operator fun > PositionBasedFilter<*>.contains(position: P): Boolean = +operator fun

> PositionBasedFilter<*>.contains(position: P): Boolean = (this as PositionBasedFilter

).contains(position) context(_: Incarnation) @@ -63,7 +63,7 @@ fun , I : Incarnation> simulation( @Suppress("UNCHECKED_CAST") override fun > getWith(values: Map): Simulation = - (if(values.isEmpty()) defaultEnvironment else getWithTyped(values)) as Simulation + (if (values.isEmpty()) defaultEnvironment else getWithTyped(values)) as Simulation private fun getWithTyped(values: Map): Simulation { logger.debug("Creating simulation with variables: {}", values) @@ -85,7 +85,7 @@ fun , I : Incarnation> simulation( override fun makePosition(coordinates: DoubleArray) = nope() override fun moveNodeToPosition(node: Node, newPosition: P) = nope() fun nope(): Nothing = error( - "The empty environment cannot generate positions, and does not support the insertion of nodes." + "The empty environment cannot generate positions, and does not support the insertion of nodes.", ) } val exporters = mutableListOf>() From f292e0d642ac948674faef336df888206d2d4fef Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 9 Feb 2026 21:02:42 +0100 Subject: [PATCH 166/196] style: apply KTLintFormat --- .../it/unibo/alchemist/dsl/TestContents.kt | 5 ++-- .../it/unibo/alchemist/dsl/TestDeployments.kt | 30 ++++++++++--------- .../it/unibo/alchemist/dsl/TestVariables.kt | 17 ++++++----- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt index 3637893e42..b2aec4fb6c 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -10,7 +10,6 @@ package it.unibo.alchemist.dsl import it.unibo.alchemist.boundary.kotlindsl.environment -import it.unibo.alchemist.boundary.kotlindsl.simulation import it.unibo.alchemist.boundary.kotlindsl.simulation2D import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.incarnations.SAPEREIncarnation @@ -26,7 +25,7 @@ class TestContents { deployments { deploy(point(0.0, 0.0)) { contents { - - "test" to listOf(LsaMolecule("1")) + -"test" to listOf(LsaMolecule("1")) } } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt index f090617fc3..61804a41d9 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt @@ -37,10 +37,11 @@ class TestDeployments { val loader = simulation2D(SAPEREIncarnation()) { environment { deployments { - val point = point(0.0, 0.0) - deploy(point) - deploy(point(1.0, 1.0)) - }} + val point = point(0.0, 0.0) + deploy(point) + deploy(point(1.0, 1.0)) + } + } } loader.launch(loader.launcher) @@ -51,17 +52,18 @@ class TestDeployments { val loader = simulation2D(SAPEREIncarnation()) { environment { deployments { - val grid = grid( - 1.0, - 1.0, - 5.0, - 5.0, - 1.0, - 1.0, - ) - deploy(grid) + val grid = grid( + 1.0, + 1.0, + 5.0, + 5.0, + 1.0, + 1.0, + ) + deploy(grid) + } } - }} + } loader.launch(loader.launcher) } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt index bf385fea3e..feefc69f12 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt @@ -77,16 +77,17 @@ class TestVariables { val mSize = -linearVariable val sourceStart = mSize / geometricVariable val sourceSize = linearVariable / 5.0 -environment { - deployments { - deploy(point(0.0, 0.0)) { - contents { - - "mSize" to mSize - - "sourceStart" to sourceStart - - "sourceSize" to sourceSize + environment { + deployments { + deploy(point(0.0, 0.0)) { + contents { + -"mSize" to mSize + -"sourceStart" to sourceStart + -"sourceSize" to sourceSize + } } } - }} + } } loader.variables.size shouldBe 2 loader.dependentVariables.size shouldBe 0 From 4c3856352549fa8cd12c36815081d5289cd392d8 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 9 Feb 2026 22:02:40 +0100 Subject: [PATCH 167/196] refactor: reorganize the new DSL --- .../environments/Abstract2DEnvironment.java | 6 +- .../model/environments/AbstractEnvironment.kt | 16 +- .../model/environments/EmptyEnvironment.kt | 106 ++++++++ .../alchemist/model/deployments/Point.java | 38 ++- .../boundary/kotlindsl/AlchemistKotlinDSL.kt | 239 ++++-------------- .../alchemist/boundary/kotlindsl/DSLLoader.kt | 176 +++++++++++++ .../boundary/kotlindsl/DeploymentContext.kt | 25 +- .../PositionBasedFilterExtensions.kt | 31 +++ .../kotlindsl/SimulationContextExtensions.kt | 31 +++ .../kotlindsl}/KotlinDslProviderTest.kt | 4 +- .../kotlindsl}/LayerComparisonUtils.kt | 11 +- .../kotlindsl}/LoaderFactory.kt | 4 +- .../kotlindsl}/PerformanceComparisonTest.kt | 14 +- .../kotlindsl}/RuntimeComparisonHelper.kt | 9 +- .../kotlindsl}/SimulationsComparisons.kt | 27 +- .../kotlindsl}/StaticComparisonHelper.kt | 4 +- .../kotlindsl}/TestComparators.kt | 2 +- .../kotlindsl}/TestContents.kt | 4 +- .../kotlindsl}/TestDSLLoading.kt | 10 +- .../kotlindsl}/TestDeployments.kt | 6 +- .../kotlindsl}/TestSimulations.kt | 6 +- .../kotlindsl}/TestVariables.kt | 6 +- 22 files changed, 496 insertions(+), 279 deletions(-) create mode 100644 alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/EmptyEnvironment.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/PositionBasedFilterExtensions.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContextExtensions.kt rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/KotlinDslProviderTest.kt (95%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/LayerComparisonUtils.kt (80%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/LoaderFactory.kt (91%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/PerformanceComparisonTest.kt (94%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/RuntimeComparisonHelper.kt (98%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/SimulationsComparisons.kt (82%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/StaticComparisonHelper.kt (99%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/TestComparators.kt (99%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/TestContents.kt (87%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/TestDSLLoading.kt (96%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/TestDeployments.kt (92%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/TestSimulations.kt (81%) rename alchemist-loading/src/test/kotlin/it/unibo/alchemist/{dsl => boundary/kotlindsl}/TestVariables.kt (94%) diff --git a/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/environments/Abstract2DEnvironment.java b/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/environments/Abstract2DEnvironment.java index 858b3d0f4a..30a30b4569 100644 --- a/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/environments/Abstract2DEnvironment.java +++ b/alchemist-implementationbase/src/main/java/it/unibo/alchemist/model/environments/Abstract2DEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -53,8 +53,8 @@ protected Abstract2DEnvironment(final Incarnation incarnation) { */ @Nonnull @Override - protected P computeActualInsertionPosition(@Nonnull final Node node, @Nonnull final P p) { - return p; + protected P computeActualInsertionPosition(@Nonnull final Node node, @Nonnull final P originalPosition) { + return originalPosition; } @Override diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt index 7d413193e5..2536b645b1 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -147,11 +147,11 @@ abstract class AbstractEnvironment> protected constructor( * * @param node * the node - * @param p + * @param originalPosition * the original (requested) position * @return the actual position where the node should be located */ - protected abstract fun computeActualInsertionPosition(node: Node, p: P): P + protected abstract fun computeActualInsertionPosition(node: Node, originalPosition: P): P override fun forEach(action: Consumer?>?) { nodes.forEach(action) @@ -170,12 +170,10 @@ abstract class AbstractEnvironment> protected constructor( private fun getAllNodesInRange(center: P, range: Double): List> { require(range > 0) { "Range query must be positive (provided: $range)" } @Suppress("UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS") - val validCache = - cache ?: Caffeine - .newBuilder() - .maximumSize(1000) - .build, List>> { (pos, r) -> runQuery(pos, r) } - .also { cache = it } + val validCache = cache ?: Caffeine.newBuilder() + .maximumSize(1000) + .build, List>> { (pos, r) -> runQuery(pos, r) } + .also { cache = it } return validCache[center to range] } diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/EmptyEnvironment.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/EmptyEnvironment.kt new file mode 100644 index 0000000000..50d4ef400f --- /dev/null +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/EmptyEnvironment.kt @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.model.environments + +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Neighborhood +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import org.danilopianini.util.SpatialIndex + +/** + * An [AbstractEnvironment] implementation that intentionally provides no spatial functionality. + * + * This environment is meant as a placeholder or sentinel implementation in contexts where an [Environment] + * instance is required, but node insertion, movement, neighborhood computation, and position construction must be + * disallowed. + * + * The backing [SpatialIndex] is a no-op implementation: it never stores elements and always returns empty query + * results. Any operation that would require actual spatial support fails fast with an error. + * + * @param incarnation the [Incarnation] associated with this environment. + * @param dimensions the number of spatial dimensions exposed by this environment. + */ +class EmptyEnvironment>(incarnation: Incarnation, override val dimensions: Int = 2) : + AbstractEnvironment( + incarnation, + object : SpatialIndex> { + override val dimensions: Int = dimensions + override fun insert(element: Node, vararg position: Double) = Unit + override fun remove(element: Node, vararg position: Double) = false + override fun move(element: Node, start: DoubleArray, end: DoubleArray) = false + override fun query(vararg parallelotope: DoubleArray) = emptyList>() + }, + ) { + + /** + * This environment does not support node insertion positions. + * + * @throws UnsupportedOperationException always. + */ + override fun computeActualInsertionPosition(node: Node, originalPosition: P): P = nope() + + /** + * This environment does not support node insertion. + * + * @throws UnsupportedOperationException always. + */ + override fun nodeAdded(node: Node, position: P, neighborhood: Neighborhood) = nope() + + /** + * The origin (all zeros) for each coordinate axis. + * + * This value is provided only to satisfy the [AbstractEnvironment] contract and does not imply that + * spatial operations are supported. + */ + override val offset: DoubleArray = DoubleArray(dimensions) { 0.0 } + + /** + * The (unit) extent for each coordinate axis. + * + * This value is provided only to satisfy the [AbstractEnvironment] contract and does not imply that + * spatial operations are supported. + */ + override val size: DoubleArray = DoubleArray(dimensions) { 1.0 } + + /** + * This environment cannot create positions. + * + * @throws UnsupportedOperationException always. + */ + override fun makePosition(vararg coordinates: Number): P = nope() + + /** + * This environment cannot create positions. + * + * @throws UnsupportedOperationException always. + */ + override fun makePosition(coordinates: DoubleArray): P = nope() + + /** + * This environment does not support node movement. + * + * @throws UnsupportedOperationException always. + */ + override fun moveNodeToPosition(node: Node, newPosition: P) = nope() + + private companion object { + + /** + * Throws the failure used by all unsupported operations in [EmptyEnvironment]. + * + * @return never returns normally. + * @throws UnsupportedOperationException always. + */ + private fun nope(): Nothing = throw UnsupportedOperationException( + "The empty environment cannot generate positions, and does not support the insertion of nodes.", + ) + } +} diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java index e783ff2319..54c82a98af 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/model/deployments/Point.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -41,6 +41,42 @@ public Point(final Environment environment, final double x, final double y positionMaker = environment::makePosition; } + /** + * @param environment + * The {@link Environment} + * @param x + * x coordinate + * @param y + * y coordinate + */ + public Point(final Environment environment, final int x, final int y) { + this(environment, (double) x, (double) y); + } + + /** + * @param environment + * The {@link Environment} + * @param x + * x coordinate + * @param y + * y coordinate + */ + public Point(final Environment environment, final double x, final int y) { + this(environment, x, (double) y); + } + + /** + * @param environment + * The {@link Environment} + * @param x + * x coordinate + * @param y + * y coordinate + */ + public Point(final Environment environment, final int x, final double y) { + this(environment, (double) x, y); + } + @Override public Stream

stream() { return Stream.of(positionMaker.apply(x, y)); diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt index 93c2bf8529..acd407425c 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistKotlinDSL.kt @@ -9,213 +9,62 @@ package it.unibo.alchemist.boundary.kotlindsl -import it.unibo.alchemist.boundary.DependentVariable -import it.unibo.alchemist.boundary.Exporter -import it.unibo.alchemist.boundary.Extractor -import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.OutputMonitor -import it.unibo.alchemist.boundary.Variable -import it.unibo.alchemist.boundary.exporters.GlobalExporter -import it.unibo.alchemist.boundary.launchers.DefaultLauncher -import it.unibo.alchemist.core.Engine -import it.unibo.alchemist.core.Simulation -import it.unibo.alchemist.model.Deployment -import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Incarnation -import it.unibo.alchemist.model.Neighborhood -import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.PositionBasedFilter -import it.unibo.alchemist.model.environments.AbstractEnvironment -import it.unibo.alchemist.model.environments.Continuous2DEnvironment -import it.unibo.alchemist.model.environments.continuous2DEnvironment import it.unibo.alchemist.model.positions.Euclidean2DPosition -import java.io.Serializable -import kotlin.properties.ReadOnlyProperty -import org.apache.commons.math3.random.MersenneTwister -import org.apache.commons.math3.random.RandomGenerator -import org.danilopianini.util.SpatialIndex -import org.slf4j.LoggerFactory - -@Suppress("UNCHECKED_CAST") -operator fun

> PositionBasedFilter<*>.contains(position: P): Boolean = - (this as PositionBasedFilter

).contains(position) - -context(_: Incarnation) -fun SimulationContext.environment( - block: context(Continuous2DEnvironment) EnvironmentContext.() -> Unit, -) = environment(continuous2DEnvironment(), block) +/** + * Creates an Alchemist [Loader] using the Kotlin DSL. + * + * The returned [Loader] encapsulates the scenario definition provided in [block] and can later be queried + * (optionally with variable bindings) to obtain a fully configured simulation instance. + * + * The [block] is executed with the provided [incarnation] available as a context receiver, and with a + * [SimulationContext] receiver, enabling the definition of the environment, deployments, exporters/monitors, + * launcher, and scenario variables. + * + * @param T the concentration type used by the simulation. + * @param P the position type used by the environment. + * @param I the specific incarnation type. + * @param incarnation the incarnation used to create domain-specific objects (molecules, nodes, reactions, etc.). + * @param block the DSL block defining the scenario. + * @return a [Loader] that can build the simulation described by [block]. + */ fun , I : Incarnation> simulation( incarnation: I, block: context(I) SimulationContext.() -> Unit, -): Loader = object : Loader { - - private val logger = LoggerFactory.getLogger("Alchemist Kotlin DSL Loader") - override var constants: Map = emptyMap() - override val remoteDependencies: List get() = TODO("Not yet implemented") - override var launcher: Launcher = DefaultLauncher() - override val dependentVariables: Map> = emptyMap() - override var variables: Map> = emptyMap() - val defaultEnvironment = getWithTyped(emptyMap()) - - @Suppress("UNCHECKED_CAST") - override fun > getWith(values: Map): Simulation = - (if (values.isEmpty()) defaultEnvironment else getWithTyped(values)) as Simulation - - private fun getWithTyped(values: Map): Simulation { - logger.debug("Creating simulation with variables: {}", values) - val loader = this - val noIndex = object : SpatialIndex> { - override val dimensions: Int = 2 - override fun insert(element: Node, vararg position: Double) = Unit - override fun remove(element: Node, vararg position: Double) = false - override fun move(element: Node, start: DoubleArray, end: DoubleArray) = false - override fun query(vararg parallelotope: DoubleArray) = emptyList>() - } - var theEnvironment: Environment = object : AbstractEnvironment(incarnation, noIndex) { - override fun computeActualInsertionPosition(node: Node, p: P): P = nope() - override fun nodeAdded(node: Node, position: P, neighborhood: Neighborhood) = nope() - override val dimensions: Int = 2 - override val offset: DoubleArray = DoubleArray(dimensions) { 0.0 } - override val size: DoubleArray = DoubleArray(dimensions) { 1.0 } - override fun makePosition(vararg coordinates: Number): P = nope() - override fun makePosition(coordinates: DoubleArray) = nope() - override fun moveNodeToPosition(node: Node, newPosition: P) = nope() - fun nope(): Nothing = error( - "The empty environment cannot generate positions, and does not support the insertion of nodes.", - ) - } - val exporters = mutableListOf>() - val monitors = mutableListOf>() - context(incarnation) { - object : SimulationContext { - - var launcherHasNotBeenSet = true - var environmentHasNotBeenSet = true - lateinit var simulationRNG: RandomGenerator - lateinit var scenarioRNG: RandomGenerator - - override fun > environment( - environment: E, - block: context(E) EnvironmentContext.() -> Unit, - ) { - if (!this::simulationRNG.isInitialized) { - simulationRNG = MersenneTwister(0L) - } - if (!this::scenarioRNG.isInitialized) { - scenarioRNG = MersenneTwister(0L) - } - check(environmentHasNotBeenSet) { - "Only one environment can be set, currently set: $theEnvironment" - } - theEnvironment = environment - environmentHasNotBeenSet = false - context(environment, simulationRNG) { - check(contextOf() == simulationRNG) - object : EnvironmentContext { - override fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) { - check(contextOf() == simulationRNG) - context(scenarioRNG) { - object : DeploymentsContext { - context(randomGenerator: RandomGenerator, environment: Environment) - override fun > deploy( - deployment: Deployment

, - nodeFactory: (P) -> Node, - block: context(RandomGenerator, Node) DeploymentContext.() -> Unit, - ) { - check(contextOf() == scenarioRNG) - deployment.forEach { position -> - context(simulationRNG) { - check(contextOf() == simulationRNG) - val node: Node = nodeFactory(position) - context(node) { - object : DeploymentContext { - override val position: P get() = position - }.block() - } - environment.addNode(node, position) - } - } - } - }.block() - } - } - }.block() - } - } - - override fun exportWith(exporter: Exporter, block: ExporterContext.() -> Unit) { - val extractors = mutableListOf>() - object : ExporterContext { - override fun Extractor<*>.unaryMinus() { - extractors += this - } - }.block() - exporter.bindDataExtractors(extractors) - exporters += exporter - } - - override fun scenarioRandomGenerator(randomGenerator: RandomGenerator) { - checkSeedCanBeSet() - scenarioRNG = randomGenerator - } - - override fun simulationRandomGenerator(randomGenerator: RandomGenerator) { - checkSeedCanBeSet() - simulationRNG = randomGenerator - } - - override fun monitor(monitor: OutputMonitor) { - monitors += monitor - } - - override fun launcher(launcher: Launcher) { - check(launcherHasNotBeenSet) { - "Only one launcher can be set, currently set: ${loader.launcher}" - } - loader.launcher = launcher - } +): Loader = DSLLoader(incarnation, block) - override fun variable(variable: Variable): ReadOnlyProperty = - ReadOnlyProperty { thisRef, property -> - variables += property.name to variable - @Suppress("UNCHECKED_CAST") - values.getOrDefault(property.name, variable.default) as V - } - - fun checkSeedCanBeSet() { - check(environmentHasNotBeenSet) { - "Seeds must be set before the environment is defined to preserve reproducibility" - } - } - }.block() - } - check(variables.keys.containsAll(values.keys)) { - val undefinedVariables = values.keys - variables.keys - """ - The following variables provided in input have no corresponding variable defined in the simulation context: - $undefinedVariables - The available variables are: ${variables.keys} - """.trimIndent() - } - val theSimulation: Simulation = Engine(theEnvironment) - if (exporters.isNotEmpty()) { - theSimulation.addOutputMonitor(GlobalExporter(exporters)) - } - monitors.forEach { monitor -> theSimulation.addOutputMonitor(monitor) } - return theSimulation - } -} - -fun > simulationOnMap( +/** + * Convenience overload of [simulation] for scenarios running in a 2D Euclidean space. + * + * This function only constrains the position type to [Euclidean2DPosition] and otherwise delegates to [simulation]. + * + * @param T the concentration type used by the simulation. + * @param I the specific incarnation type. + * @param incarnation the incarnation used to create domain-specific objects. + * @param block the DSL block defining the scenario. + * @return a [Loader] that can build the simulation described by [block]. + */ +fun > simulation2D( incarnation: I, - block: context(I) SimulationContext.() -> Unit, + block: context(I) SimulationContext.() -> Unit, ) = simulation(incarnation, block) -fun > simulation2D( +/** + * Convenience overload of [simulation] for scenarios running on geographical coordinates. + * + * This function only constrains the position type to [GeoPosition] and otherwise delegates to [simulation]. + * + * @param T the concentration type used by the simulation. + * @param I the specific incarnation type. + * @param incarnation the incarnation used to create domain-specific objects. + * @param block the DSL block defining the scenario. + * @return a [Loader] that can build the simulation described by [block]. + */ +fun > simulationOnMap( incarnation: I, - block: context(I) SimulationContext.() -> Unit, + block: context(I) SimulationContext.() -> Unit, ) = simulation(incarnation, block) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt new file mode 100644 index 0000000000..378d39f098 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.boundary.DependentVariable +import it.unibo.alchemist.boundary.Exporter +import it.unibo.alchemist.boundary.Extractor +import it.unibo.alchemist.boundary.Launcher +import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.OutputMonitor +import it.unibo.alchemist.boundary.Variable +import it.unibo.alchemist.boundary.exporters.GlobalExporter +import it.unibo.alchemist.boundary.launchers.DefaultLauncher +import it.unibo.alchemist.core.Engine +import it.unibo.alchemist.core.Simulation +import it.unibo.alchemist.model.Deployment +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.environments.EmptyEnvironment +import java.io.Serializable +import kotlin.properties.ReadOnlyProperty +import org.apache.commons.math3.random.MersenneTwister +import org.apache.commons.math3.random.RandomGenerator +import org.slf4j.LoggerFactory + +internal class DSLLoader, I : Incarnation>( + private val incarnation: I, + private val block: context(I) SimulationContext.() -> Unit, +) : Loader { + + private val logger = LoggerFactory.getLogger("Alchemist Kotlin DSL Loader") + override var constants: Map = emptyMap() + override val remoteDependencies: List get() = TODO("Not yet implemented") + override var launcher: Launcher = DefaultLauncher() + override val dependentVariables: Map> = emptyMap() + override var variables: Map> = emptyMap() + val defaultEnvironment = getWithTyped(emptyMap()) + + @Suppress("UNCHECKED_CAST") + override fun > getWith(values: Map): Simulation = + (if (values.isEmpty()) defaultEnvironment else getWithTyped(values)) as Simulation + + private fun getWithTyped(values: Map): Simulation { + logger.debug("Creating simulation with variables: {}", values) + val loader = this + var theEnvironment: Environment = EmptyEnvironment(incarnation) + val exporters = mutableListOf>() + val monitors = mutableListOf>() + context(incarnation) { + object : SimulationContext { + + var launcherHasNotBeenSet = true + var environmentHasNotBeenSet = true + lateinit var simulationRNG: RandomGenerator + lateinit var scenarioRNG: RandomGenerator + + override fun > environment( + environment: E, + block: context(E) EnvironmentContext.() -> Unit, + ) { + if (!this::simulationRNG.isInitialized) { + simulationRNG = MersenneTwister(0L) + } + if (!this::scenarioRNG.isInitialized) { + scenarioRNG = MersenneTwister(0L) + } + check(environmentHasNotBeenSet) { + "Only one environment can be set, currently set: $theEnvironment" + } + theEnvironment = environment + environmentHasNotBeenSet = false + context(environment, simulationRNG) { + check(contextOf() == simulationRNG) + object : EnvironmentContext { + override fun deployments(block: context(RandomGenerator) DeploymentsContext.() -> Unit) { + check(contextOf() == simulationRNG) + context(scenarioRNG) { + object : DeploymentsContext { + context(randomGenerator: RandomGenerator, environment: Environment) + override fun > deploy( + deployment: Deployment

, + nodeFactory: (P) -> Node, + block: context(RandomGenerator, Node) DeploymentContext.() -> Unit, + ) { + check(contextOf() == scenarioRNG) + deployment.forEach { position -> + context(simulationRNG) { + check(contextOf() == simulationRNG) + val node: Node = nodeFactory(position) + context(node) { + object : DeploymentContext { + override val position: P get() = position + }.block() + } + environment.addNode(node, position) + } + } + } + }.block() + } + } + }.block() + } + } + + override fun exportWith(exporter: Exporter, block: ExporterContext.() -> Unit) { + val extractors = mutableListOf>() + object : ExporterContext { + override fun Extractor<*>.unaryMinus() { + extractors += this + } + }.block() + exporter.bindDataExtractors(extractors) + exporters += exporter + } + + override fun scenarioRandomGenerator(randomGenerator: RandomGenerator) { + checkSeedCanBeSet() + scenarioRNG = randomGenerator + } + + override fun simulationRandomGenerator(randomGenerator: RandomGenerator) { + checkSeedCanBeSet() + simulationRNG = randomGenerator + } + + override fun monitor(monitor: OutputMonitor) { + monitors += monitor + } + + override fun launcher(launcher: Launcher) { + check(launcherHasNotBeenSet) { + "Only one launcher can be set, currently set: ${loader.launcher}" + } + loader.launcher = launcher + } + + override fun variable(variable: Variable): ReadOnlyProperty = + ReadOnlyProperty { thisRef, property -> + variables += property.name to variable + @Suppress("UNCHECKED_CAST") + values.getOrDefault(property.name, variable.default) as V + } + + fun checkSeedCanBeSet() { + check(environmentHasNotBeenSet) { + "Seeds must be set before the environment is defined to preserve reproducibility" + } + } + }.block() + } + check(variables.keys.containsAll(values.keys)) { + val undefinedVariables = values.keys - variables.keys + """ + The following variables provided in input have no corresponding variable defined in the simulation context: + $undefinedVariables + The available variables are: ${variables.keys} + """.trimIndent() + } + val theSimulation: Simulation = Engine(theEnvironment) + if (exporters.isNotEmpty()) { + theSimulation.addOutputMonitor(GlobalExporter(exporters)) + } + monitors.forEach { monitor -> theSimulation.addOutputMonitor(monitor) } + return theSimulation + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt index 4ca0973fb6..cdb35dcfe6 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt @@ -96,7 +96,8 @@ interface DeploymentContext> { * The optional [block] can be used to attach actions and conditions through [ActionableContext]. * * @param program an incarnation-specific reaction/program descriptor, possibly `null`. - * @param timeDistribution either a concrete [TimeDistribution] instance, an incarnation-specific descriptor, or `null`. + * @param timeDistribution + * either a concrete [TimeDistribution] instance, an incarnation-specific descriptor, or `null`. * @param block an optional configuration block for actions and conditions. */ context( @@ -138,22 +139,13 @@ interface DeploymentContext> { private companion object { - /** - * Creates a [TimeDistribution] through the current [Incarnation]. - * - * The [parameter] is forwarded to [Incarnation.createTimeDistribution] and its interpretation depends on - * the concrete incarnation. - * - * @param parameter an incarnation-specific descriptor, or `null`. - * @return a time distribution suitable for scheduling reactions on the given [node] in the given [environment]. - */ context( incarnation: Incarnation, randomGenerator: RandomGenerator, environment: Environment, node: Node ) - fun > makeTimeDistribution(parameter: Any? = null): TimeDistribution = + private fun > makeTimeDistribution(parameter: Any? = null): TimeDistribution = incarnation.createTimeDistribution( randomGenerator, environment, @@ -161,15 +153,6 @@ interface DeploymentContext> { parameter, ) - /** - * Creates a [Reaction] through the current [Incarnation] using the provided [timeDistribution]. - * - * Note: the [descriptor] parameter is currently ignored, and the reaction is created with a `null` - * program descriptor, delegating program selection to the incarnation. - * - * @param descriptor an optional descriptor that is currently not used. - * @return a reaction created by the incarnation for the given context. - */ context( incarnation: Incarnation, randomGenerator: RandomGenerator, @@ -177,7 +160,7 @@ interface DeploymentContext> { node: Node, timeDistribution: TimeDistribution ) - fun > makeReaction(descriptor: String?): Reaction = incarnation.createReaction( + private fun > makeReaction(descriptor: String?): Reaction = incarnation.createReaction( randomGenerator, environment, node, diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/PositionBasedFilterExtensions.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/PositionBasedFilterExtensions.kt new file mode 100644 index 0000000000..8fa353ffc6 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/PositionBasedFilterExtensions.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.PositionBasedFilter + +/** + * Enables the Kotlin `in` operator for [PositionBasedFilter] instances. + * + * This is a convenience extension that allows writing `position in filter` instead of + * `filter.contains(position)`, even when the filter is available with a star-projected type. + * + * Since [PositionBasedFilter] is generic in the position type, this operator performs an unchecked cast to + * [PositionBasedFilter]<[P]>. The caller is responsible for ensuring that the runtime filter expects positions + * compatible with [P]; otherwise, the underlying implementation may throw at runtime or behave unexpectedly. + * + * @param P the position type. + * @param position the position being tested for inclusion. + * @return `true` if [position] is contained in this filter, `false` otherwise. + */ +@Suppress("UNCHECKED_CAST") +operator fun

> PositionBasedFilter<*>.contains(position: P): Boolean = + (this as PositionBasedFilter

).contains(position) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContextExtensions.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContextExtensions.kt new file mode 100644 index 0000000000..55734eacf7 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContextExtensions.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +// TODO: Detekt false positive. Remove once Detekt supports context parameters. +@file:Suppress("UndocumentedPublicFunction") + +package it.unibo.alchemist.boundary.kotlindsl + +import it.unibo.alchemist.model.Incarnation +import it.unibo.alchemist.model.environments.Continuous2DEnvironment +import it.unibo.alchemist.model.environments.continuous2DEnvironment +import it.unibo.alchemist.model.positions.Euclidean2DPosition + +/** + * Convenience overload that installs a default [Continuous2DEnvironment] and configures it via [block]. + * + * This function is available only when an [Incarnation] for [Euclidean2DPosition] is in scope, and it delegates to + * [SimulationContext.environment] by creating a new environment through [continuous2DEnvironment]. + * + * @param block the environment configuration block executed with the created environment as a context receiver. + */ +context(_: Incarnation) +fun SimulationContext.environment( + block: context(Continuous2DEnvironment) EnvironmentContext.() -> Unit, +) = environment(continuous2DEnvironment(), block) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt similarity index 95% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt index ad9239286f..c41e4e0ab3 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -7,7 +7,7 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.boundary.LoadAlchemist import java.nio.file.Files diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/LayerComparisonUtils.kt similarity index 80% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/LayerComparisonUtils.kt index e9c2e3a4d0..00019268db 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LayerComparisonUtils.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/LayerComparisonUtils.kt @@ -1,4 +1,13 @@ -package it.unibo.alchemist.dsl +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.Position diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/LoaderFactory.kt similarity index 91% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/LoaderFactory.kt index 385fc34806..dbe7018fed 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/LoaderFactory.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/LoaderFactory.kt @@ -1,12 +1,12 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.boundary.LoadAlchemist import it.unibo.alchemist.boundary.Loader diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt similarity index 94% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt index cc323081bf..f9d5dba2f0 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/PerformanceComparisonTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt @@ -1,8 +1,18 @@ -package it.unibo.alchemist.dsl +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.boundary.LoadAlchemist import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.model.Position +import java.io.ByteArrayOutputStream import java.io.File import java.io.PrintStream import java.util.Locale @@ -97,7 +107,7 @@ class PerformanceComparisonTest { ): PerformanceStats { val originalOut = System.out val originalErr = System.err - val nullStream = PrintStream(java.io.ByteArrayOutputStream()) + val nullStream = PrintStream(ByteArrayOutputStream()) println("\n=== $testHeader ===") println("Resource: $yamlResource") println("Iterations: $iterations\n") diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt similarity index 98% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt index f4472d6679..08557931c9 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/RuntimeComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt @@ -1,12 +1,12 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.core.Simulation @@ -21,7 +21,6 @@ import it.unibo.alchemist.model.terminators.StableForSteps import it.unibo.alchemist.model.terminators.StepCount import it.unibo.alchemist.model.times.DoubleTime import kotlin.math.abs -import kotlin.math.max import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.fail @@ -45,8 +44,6 @@ object RuntimeComparisonHelper { * Only one termination method should be provided. * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). * Only one termination method should be provided. - * @param timeTolerance Tolerance for time comparison in seconds (default: 0.01s) - * @param positionTolerance Maximum distance between positions to consider them matching. * If null, calculated as max(timeTolerance * 10, 1e-6). * For random movement tests, consider using a larger value (e.g., 1.0 or more). * @@ -379,8 +376,6 @@ object RuntimeComparisonHelper { /** * Compares node states after runtime execution using position-based matching with tolerance. - * - * @param positionTolerance Maximum distance between positions to consider them matching (default: 1e-6) */ private fun > compareRuntimeNodeStates(dslEnv: Environment, yamlEnv: Environment) { println("Comparing runtime node states...") diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationsComparisons.kt similarity index 82% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationsComparisons.kt index afa7bcc84c..7eb79d77b8 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/SimulationsComparisons.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationsComparisons.kt @@ -6,19 +6,28 @@ * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl -import it.unibo.alchemist.model.Position -import org.junit.jupiter.api.Test +import io.kotest.core.spec.style.AnnotationSpec +import it.unibo.alchemist.model.deployments.point +import it.unibo.alchemist.model.incarnations.SAPEREIncarnation +import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance class SimulationsComparisons { - // TODO: rewrite -// @Test -// fun test01() { -// { DslLoaderFunctions.test01Nodes() }.shouldEqual("dsl/yml/01-nodes.yml") -// } -// + @AnnotationSpec.Test + fun test01() { + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(5.0)) + deployments { + deploy(point(0, 0)) + deploy(point(1, 1)) + } + } + }.shouldEqual("dsl/yml/01-nodes.yml") + } + // @Test // fun test02() { // { DslLoaderFunctions.test02ManyNodes() }.shouldEqual("dsl/yml/02-manynodes.yml") diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/StaticComparisonHelper.kt similarity index 99% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/StaticComparisonHelper.kt index 23c3c8a44d..10daf1002f 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/StaticComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/StaticComparisonHelper.kt @@ -1,12 +1,12 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.boundary.Exporter import it.unibo.alchemist.boundary.Loader diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestComparators.kt similarity index 99% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestComparators.kt index e97029b049..c29371d5a2 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestComparators.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestComparators.kt @@ -6,7 +6,7 @@ * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.model.Position diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestContents.kt similarity index 87% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestContents.kt index b2aec4fb6c..f6c4e88ee1 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestContents.kt @@ -7,10 +7,8 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl -import it.unibo.alchemist.boundary.kotlindsl.environment -import it.unibo.alchemist.boundary.kotlindsl.simulation2D import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.sapere.molecules.LsaMolecule diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDSLLoading.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestDSLLoading.kt similarity index 96% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDSLLoading.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestDSLLoading.kt index 33dbfe7509..c30e373c00 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDSLLoading.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestDSLLoading.kt @@ -7,19 +7,13 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl import another.location.SimpleMonitor import it.unibo.alchemist.boundary.exporters.CSVExporter import it.unibo.alchemist.boundary.exportfilters.CommonFilters import it.unibo.alchemist.boundary.extractors.Time import it.unibo.alchemist.boundary.extractors.moleculeReader -import it.unibo.alchemist.boundary.kotlindsl.ActionableContext -import it.unibo.alchemist.boundary.kotlindsl.contains -import it.unibo.alchemist.boundary.kotlindsl.environment -import it.unibo.alchemist.boundary.kotlindsl.simulation -import it.unibo.alchemist.boundary.kotlindsl.simulation2D -import it.unibo.alchemist.boundary.kotlindsl.simulationOnMap import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.jakta.timedistributions.JaktaTimeDistribution @@ -65,7 +59,7 @@ class TestDSLLoading { networkModel(ConnectWithinDistance(0.5)) deployments { deploy(makePerturbedGridForTesting()) { - if (position in Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { + if (position contains Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { contents { -"token, 0, []" } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestDeployments.kt similarity index 92% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestDeployments.kt index 61804a41d9..13086dc9aa 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestDeployments.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestDeployments.kt @@ -7,10 +7,8 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl -import it.unibo.alchemist.boundary.kotlindsl.environment -import it.unibo.alchemist.boundary.kotlindsl.simulation2D import it.unibo.alchemist.model.deployments.grid import it.unibo.alchemist.model.deployments.point import it.unibo.alchemist.model.incarnations.SAPEREIncarnation @@ -28,7 +26,6 @@ class TestDeployments { } } } - loader.launch(loader.launcher) } @@ -43,7 +40,6 @@ class TestDeployments { } } } - loader.launch(loader.launcher) } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestSimulations.kt similarity index 81% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestSimulations.kt index 2d691ada08..5c84eac3ba 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestSimulations.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestSimulations.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -7,10 +7,8 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl -import it.unibo.alchemist.boundary.kotlindsl.environment -import it.unibo.alchemist.boundary.kotlindsl.simulation2D import it.unibo.alchemist.model.incarnations.SAPEREIncarnation import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance import org.junit.jupiter.api.Test diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt similarity index 94% rename from alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt rename to alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt index feefc69f12..cb58e5d903 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/dsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -7,15 +7,13 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.dsl +package it.unibo.alchemist.boundary.kotlindsl import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.booleans.shouldBeTrue import io.kotest.matchers.doubles.shouldBeExactly import io.kotest.matchers.maps.shouldNotBeEmpty import io.kotest.matchers.shouldBe -import it.unibo.alchemist.boundary.kotlindsl.environment -import it.unibo.alchemist.boundary.kotlindsl.simulation2D import it.unibo.alchemist.boundary.variables.GeometricVariable import it.unibo.alchemist.boundary.variables.LinearVariable import it.unibo.alchemist.model.Position From 86161137c10f22066d3c71d3a556ca2cd4431149 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 9 Feb 2026 22:11:16 +0100 Subject: [PATCH 168/196] fix: improve no-op implementation in EmptyEnvironment --- .../alchemist/model/environments/EmptyEnvironment.kt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/EmptyEnvironment.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/EmptyEnvironment.kt index 50d4ef400f..e283bfc1b5 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/EmptyEnvironment.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/EmptyEnvironment.kt @@ -18,13 +18,11 @@ import org.danilopianini.util.SpatialIndex /** * An [AbstractEnvironment] implementation that intentionally provides no spatial functionality. * - * This environment is meant as a placeholder or sentinel implementation in contexts where an [Environment] + * This environment is meant as a placeholder or sentinel implementation in contexts where an + * [it.unibo.alchemist.model.Environment] * instance is required, but node insertion, movement, neighborhood computation, and position construction must be * disallowed. * - * The backing [SpatialIndex] is a no-op implementation: it never stores elements and always returns empty query - * results. Any operation that would require actual spatial support fails fast with an error. - * * @param incarnation the [Incarnation] associated with this environment. * @param dimensions the number of spatial dimensions exposed by this environment. */ @@ -33,9 +31,9 @@ class EmptyEnvironment>(incarnation: Incarnation, overr incarnation, object : SpatialIndex> { override val dimensions: Int = dimensions - override fun insert(element: Node, vararg position: Double) = Unit - override fun remove(element: Node, vararg position: Double) = false - override fun move(element: Node, start: DoubleArray, end: DoubleArray) = false + override fun insert(element: Node, vararg position: Double) = nope() + override fun remove(element: Node, vararg position: Double) = nope() + override fun move(element: Node, start: DoubleArray, end: DoubleArray) = nope() override fun query(vararg parallelotope: DoubleArray) = emptyList>() }, ) { From 40ca49b893b37e5811f01a0629ebe209e4e2cc83 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 9 Feb 2026 22:16:21 +0100 Subject: [PATCH 169/196] refactor: change NoNode from object to data object and remove unused equals/hashCode methods --- .../alchemist/model/incarnations/ProtelisIncarnation.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt index c51405159f..57e3e3d56a 100644 --- a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt +++ b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt @@ -45,7 +45,6 @@ import java.util.Optional import java.util.concurrent.Semaphore import java.util.concurrent.TimeUnit import javax.annotation.Nonnull -import kotlin.text.get import org.apache.commons.math3.random.MersenneTwister import org.apache.commons.math3.random.RandomGenerator import org.protelis.lang.ProtelisLoader @@ -358,7 +357,7 @@ class ProtelisIncarnation

> : Incarnation { } } - private object NoNode : Node { + private data object NoNode : Node { @Serial private const val serialVersionUID = 1L @@ -390,10 +389,6 @@ class ProtelisIncarnation

> : Incarnation { override fun setConcentration(molecule: Molecule, concentration: Any) = notImplemented() - override fun equals(other: Any?): Boolean = other === this - - override fun hashCode(): Int = -1 - override fun addProperty(nodeProperty: NodeProperty) = notImplemented() @Suppress("UnusedPrivateMember") From a1362120dfd3e9874d718220bdcae0e1fccb1bc1 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Tue, 10 Feb 2026 12:27:40 +0100 Subject: [PATCH 170/196] chore: replace associate with associateWith for clarity in NetworkCentroid --- .../it/unibo/alchemist/boundary/extractors/NetworkCentroid.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NetworkCentroid.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NetworkCentroid.kt index 25ad0f2ed2..8be413230f 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NetworkCentroid.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/extractors/NetworkCentroid.kt @@ -26,7 +26,7 @@ class NetworkCentroid : Extractor { time: Time, step: Long, ): Map = when (environment.nodeCount) { - 0 -> columnNames.associate { it to NaN } + 0 -> columnNames.associateWith { NaN } else -> environment.networkHub().toList().mapIndexed { index, value -> columnNames[index] to value From cdd3eebfb71ecefe6946b0c8c182b0a9e9926558 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Tue, 10 Feb 2026 12:28:09 +0100 Subject: [PATCH 171/196] refactor: move isMeaningful extension property to companion object in SimpleNetworkArrivals --- .../SimpleNetworkArrivals.kt | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/SimpleNetworkArrivals.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/SimpleNetworkArrivals.kt index 6413c3ccb8..35c874bcfc 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/SimpleNetworkArrivals.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/SimpleNetworkArrivals.kt @@ -29,14 +29,6 @@ import java.lang.IllegalStateException * then it will get used as a constant delay. Otherwise, the String will be used within [Incarnation.getProperty] * */ - -private val Molecule?.isMeaningful: Molecule? - get() = this?.takeUnless { name.isNullOrBlank() } - -/** - * A time distribution that simulates network packet arrivals based on EdgeCloudSim model. - * Computes delays based on propagation delay and packet transmission time (packet size / bandwidth). - */ class SimpleNetworkArrivals private constructor( /** The incarnation used to resolve properties from nodes. */ val incarnation: Incarnation, @@ -161,7 +153,7 @@ class SimpleNetworkArrivals private constructor( ).let { bw -> accessPointIdentificator?.let { id -> if (node.isAccessPoint || myNeighborhood.isEmpty()) { - bw / Math.max(myNeighborhood.size, 1) + bw / myNeighborhood.size.coerceAtLeast(1) } else { val accesspoints = myNeighborhood.filter { it.isAccessPoint } when (accesspoints.size) { @@ -218,6 +210,11 @@ class SimpleNetworkArrivals private constructor( ) override fun getRate(): Double = 1 / (propagationDelay + packetSize / bandwidth) -} -private operator fun Time.plus(other: Double) = DoubleTime(toDouble() + other) + private companion object { + private val Molecule?.isMeaningful: Molecule? + get() = this?.takeUnless { name.isNullOrBlank() } + + private operator fun Time.plus(other: Double) = DoubleTime(toDouble() + other) + } +} From 124d06dc6734c6f7ef2df9fc2963633ec90278c7 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Tue, 10 Feb 2026 12:28:20 +0100 Subject: [PATCH 172/196] fix: ensure launcher can only be set once in DSLLoader --- .../kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt index 378d39f098..e9d7856d42 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt @@ -141,6 +141,7 @@ internal class DSLLoader, I : Incarnation>( check(launcherHasNotBeenSet) { "Only one launcher can be set, currently set: ${loader.launcher}" } + launcherHasNotBeenSet = false loader.launcher = launcher } From e05b2ef217d8abe3af380cc73fbed63a4afded36 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 11 Feb 2026 18:12:22 +0100 Subject: [PATCH 173/196] docs: fix dokka dangling links --- .../src/main/kotlin/it/unibo/alchemist/boundary/Extractor.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Extractor.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Extractor.kt index 54f2ab1f7f..cf47d35740 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Extractor.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Extractor.kt @@ -25,8 +25,7 @@ interface Extractor { * Extracts properties from an environment. The returned map must either: * - contain a single element, * - have the keys matching [columnNames], or - * - be iterable in predictable order - * (namely, implement [SortedMap] or extend one of [LinkedHashMap] or [ConcurrentLinkedHashMap]). + * - be iterable in predictable order. * * @param environment * the {@link Environment} @@ -42,7 +41,7 @@ interface Extractor { * - contain a single element, * - have the keys matching [columnNames], or * - be iterable in predictable order - * (namely, implement [SortedMap] or extend [LinkedHashMap]). + * (namely, implement [java.util.SortedMap] or extend [LinkedHashMap]). */ fun extractData( environment: Environment, From 3322c5f2fa3962303cc636670abaf46686269963 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 11 Feb 2026 18:18:26 +0100 Subject: [PATCH 174/196] chore: drop unused `VariableProvider` --- .../boundary/kotlindsl/VariableProvider.kt | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableProvider.kt diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableProvider.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableProvider.kt deleted file mode 100644 index 4dc34d3fad..0000000000 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableProvider.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.kotlindsl - -import java.io.Serializable -import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KProperty - -/** - * Contract for DSL components that provide delegated, read-only variables. - * - * This interface integrates with Kotlin's delegated property mechanism by exposing [provideDelegate]. - * Implementations can intercept property delegation at declaration time to: - * - register the variable under the chosen property name; - * - return a [ReadOnlyProperty] that supplies the actual value at access time. - * - * The value type [V] must be [Serializable] to match Alchemist's requirements for scenario variables. - * - * @param V the type of value provided by the delegate. - */ -interface VariableProvider { - - /** - * Intercepts the delegation of a property and returns the [ReadOnlyProperty] that will supply its value. - * - * Implementations typically use [property.name] as the variable identifier and may use [thisRef] to - * associate the delegate with the owning instance, if needed. - * - * @param thisRef the object on which the property is delegated (or `null` for top-level properties). - * @param property the metadata of the delegated property. - * @return a read-only property delegate providing values of type [V]. - */ - operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): ReadOnlyProperty -} From 3fb533b847b87f2894c833608a52d645aef6a4fa Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 11 Feb 2026 18:19:39 +0100 Subject: [PATCH 175/196] test: replace 'contains' with 'in' for position check in TestDSLLoading --- .../it/unibo/alchemist/boundary/kotlindsl/TestDSLLoading.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestDSLLoading.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestDSLLoading.kt index c30e373c00..c3f0ea9635 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestDSLLoading.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestDSLLoading.kt @@ -59,7 +59,7 @@ class TestDSLLoading { networkModel(ConnectWithinDistance(0.5)) deployments { deploy(makePerturbedGridForTesting()) { - if (position contains Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { + if (position in Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { contents { -"token, 0, []" } From d2c3da0285bf08af3c262615f60d48885d0ed6fc Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 11 Feb 2026 18:21:49 +0100 Subject: [PATCH 176/196] test: use diamond operator for Grid instantiation in TestGrid --- .../java/it/unibo/alchemist/model/deployments/TestGrid.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alchemist-loading/src/test/java/it/unibo/alchemist/model/deployments/TestGrid.java b/alchemist-loading/src/test/java/it/unibo/alchemist/model/deployments/TestGrid.java index 336a0d43f9..58340728fd 100644 --- a/alchemist-loading/src/test/java/it/unibo/alchemist/model/deployments/TestGrid.java +++ b/alchemist-loading/src/test/java/it/unibo/alchemist/model/deployments/TestGrid.java @@ -39,7 +39,7 @@ private static MersenneTwister randomGenerator() { @Test void testVerticalLine() { test(10, 1, 9.9); - assertEquals(10L, new Grid(environment(), randomGenerator(), 0, 0, 1, 10, 1, 1, 0, 0).stream().count()); + assertEquals(10L, new Grid<>(environment(), randomGenerator(), 0, 0, 1, 10, 1, 1, 0, 0).stream().count()); } /** @@ -81,7 +81,7 @@ void test10x10() { void testbug73() { assertEquals( 20L * 20, - new Grid(environment(), randomGenerator(), 0, 0, 20, 20, 1, 1, 0.8, 0.8) + new Grid<>(environment(), randomGenerator(), 0, 0, 20, 20, 1, 1, 0.8, 0.8) .stream().distinct().count() ); } @@ -97,7 +97,7 @@ void test10x10negative() { private void test(final long expected, final double x, final double y) { assertEquals( expected, - new Grid( + new Grid<>( environment(), new MersenneTwister(), 0, From cc3d73d4f257ad1bdfe688001d340271eb78e353 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Wed, 11 Feb 2026 18:23:04 +0100 Subject: [PATCH 177/196] test: add suppression for name shadowing in TestVariables --- .../it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt index cb58e5d903..28fa49f38a 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt @@ -60,6 +60,7 @@ class TestVariables { val rate: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) println("First declaration of rate: $rate") shouldThrow { + @Suppress("NoNameShadowing") // We are shadowing on purpose to test that it is not allowed val rate: Double by variable(GeometricVariable(2.0, 1.0, 5.0, 1)) println("This line should not be printed: $rate") } From 5fd3c90bcaf0a53a9c66c824dca8c713a491378b Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 12 Feb 2026 11:10:28 +0100 Subject: [PATCH 178/196] feat: implement VariableDelegateFactory for DSL variable delegation --- .../alchemist/boundary/kotlindsl/DSLLoader.kt | 14 ++++++++--- .../kotlindsl/VariableDelegateFactory.kt | 25 +++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableDelegateFactory.kt diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt index e9d7856d42..9a873d35f4 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt @@ -145,11 +145,17 @@ internal class DSLLoader, I : Incarnation>( loader.launcher = launcher } - override fun variable(variable: Variable): ReadOnlyProperty = - ReadOnlyProperty { thisRef, property -> + override fun variable(variable: Variable) = + VariableDelegateFactory { _, property -> + check(property.name !in variables.keys) { + "Error: variable '${property.name}' defined multiple times. " + + "The first definition binds to: ${variables[property.name]}" + } variables += property.name to variable - @Suppress("UNCHECKED_CAST") - values.getOrDefault(property.name, variable.default) as V + ReadOnlyProperty { _, _ -> + @Suppress("UNCHECKED_CAST") + values.getOrDefault(property.name, variable.default) as V + } } fun checkSeedCanBeSet() { diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableDelegateFactory.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableDelegateFactory.kt new file mode 100644 index 0000000000..22ea30db41 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/VariableDelegateFactory.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.kotlindsl + +import java.io.Serializable +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty + +/** + * Factory for variable delegates, which are used to implement the `by variable(...)` syntax in the DSL. + */ +fun interface VariableDelegateFactory { + + /** + * Provides a delegate for a variable property. + */ + operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): ReadOnlyProperty +} From 08c7918732eb03f8af0c3b64cc4833a5de9fae63 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 12 Feb 2026 11:13:10 +0100 Subject: [PATCH 179/196] feat: refactor simulation setup and environment configuration in performance script --- .../dsl/kts/19-performance.alchemist.kts | 133 +++++------------- 1 file changed, 38 insertions(+), 95 deletions(-) diff --git a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts index 4e650dc05f..c215f64456 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts @@ -9,109 +9,52 @@ package dsl.kts import another.location.SimpleMonitor -import it.unibo.alchemist.boundary.dsl.Dsl.incarnation -import it.unibo.alchemist.boundary.dsl.Dsl.simulation import it.unibo.alchemist.boundary.extractors.Time -import org.apache.commons.math3.random.MersenneTwister - -simulation(SAPEREIncarnation()) { - simulationGenerator = MersenneTwister(24L) - scenarioGenerator = MersenneTwister(42L) - - networkModel = ConnectWithinDistance(0.5) +simulation2D(SAPEREIncarnation()) { + simulationSeed(24L) + scenarioSeed(42L) val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) - - val mSize by variable { -size } - val sourceStart by variable { mSize / 10.0 } - val sourceSize by variable { size / 5.0 } - - layer { - molecule = "A" - layer = StepLayer(2.0, 2.0, 100.0, 0.0) - } - layer { - molecule = "B" - layer = StepLayer(-2.0, -2.0, 0.0, 100.0) - } - layer { - molecule = "C" - layer = StepLayer(0.0, 0.0, 50.0, 50.0) - } - - monitors { +SimpleMonitor()} - - exporter { - type = CSVExporter( - "performance_test", - 1.0, - ) - data( - Time(), - moleculeReader( - "token", - null, - CommonFilters.NOFILTER.filteringPolicy, - emptyList(), - ), - ) - } - - deployments { - deploy( - circle( - 200, - 0.0, - 0.0, - 20.0, - ), - ) { - all { - molecule = "basemolecule" + environment { + networkModel(ConnectWithinDistance(0.5)) + val mSize = -size + val sourceStart = mSize / 10.0 + val sourceSize = size / 5.0 + layer("A", StepLayer(2.0, 2.0, concentrationOf(100.0), concentrationOf(0.0))) + layer("B", StepLayer(-2.0, -2.0, concentrationOf(0.0), concentrationOf(100.0))) + layer("C", StepLayer(0.0, 0.0, concentrationOf(50.0), concentrationOf(50.0))) + monitor(SimpleMonitor()) + deployments { + deploy(circle(200, 0.0, 0.0, 20.0)) { + contents { + - "basemolecule" + if (position in Rectangle(-5.0, -5.0, 10.0, 10.0)) { + - "centermolecule" + } + program("1", 1.0) + program("2", 2.0) } } - inside(RectangleFilter(-5.0, -5.0, 10.0, 10.0)) { - molecule = "centermolecule" - } - programs { - all { - timeDistribution("1") - program = "{basemolecule} --> {processed}" + deploy(grid(mSize, mSize, size, size, 0.25, 0.25, 0.1, 0.1)) { + contents { + - "gridmolecule" + if (position in Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { + -"token, 0, []" + } + if (position in Rectangle(-2.0, -2.0, 4.0, 4.0)) { + -"filteredmolecule" + } } - all { - program = "{processed} --> +{basemolecule}" - } - } - } - deploy( - grid( - mSize, mSize, size, size, - 0.25, 0.25, 0.1, 0.1, - ), - ) { - all { - molecule = "gridmolecule" - } - inside(RectangleFilter(sourceStart, sourceStart, sourceSize, sourceSize)) { - molecule = "token, 0, []" - } - inside(RectangleFilter(-2.0, -2.0, 4.0, 4.0)) { - molecule = "filteredmolecule" - } - programs { - all { - timeDistribution(rate.toString()) - program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" - } - all { - program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" - } - inside(RectangleFilter(-1.0, -1.0, 2.0, 2.0)) { - timeDistribution("0.5") - program = "{filteredmolecule} --> {active}" + program("{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}", rate) + program("{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}") + if (position in Rectangle(-1.0, -1.0, 2.0, 2.0)) { + program("{filteredmolecule} --> {active}", 0.5) } } } } + exportWith(CSVExporter("performance_test", 1.0)) { + -Time() + -moleculeReader("token", null, CommonFilters.NOFILTER.filteringPolicy, emptyList()) + } } - From cb93dae743a1e569238ad036a8e24b7bea705cf7 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 12 Feb 2026 11:13:47 +0100 Subject: [PATCH 180/196] feat: update SimulationContext to include VariableDelegateFactory and concentration creation --- .../alchemist/boundary/kotlindsl/SimulationContext.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt index a517635e78..8f438a2c15 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContext.kt @@ -14,6 +14,7 @@ import it.unibo.alchemist.boundary.Launcher import it.unibo.alchemist.boundary.OutputMonitor import it.unibo.alchemist.boundary.Variable import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.Incarnation import it.unibo.alchemist.model.Position import java.io.Serializable import kotlin.properties.ReadOnlyProperty @@ -37,6 +38,8 @@ import org.apache.commons.math3.random.RandomGenerator * @param T the concentration type used by the simulation. * @param P the position type used by the environment. */ +// Detekt false positive. Remove once Detekt supports context parameters. +@Suppress("UndocumentedPublicFunction") interface SimulationContext> { /** @@ -124,5 +127,11 @@ interface SimulationContext> { * @param variable the variable definition. * @return a property delegate providing the resolved variable value. */ - fun variable(variable: Variable): ReadOnlyProperty + fun variable(variable: Variable): VariableDelegateFactory + + /** + * Creates a concentration value using the current [Incarnation]. + */ + context(incarnation: Incarnation) + fun concentrationOf(concentration: Any?): T = incarnation.createConcentration(concentration) } From c370bb45a6ab4fda90f761876c7aeb3a6ca38e5d Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 12 Feb 2026 11:14:23 +0100 Subject: [PATCH 181/196] feat: enhance createConcentration method to handle null and collection descriptors --- .../model/incarnations/SAPEREIncarnation.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java index 41a7b614f3..23f5e886b1 100644 --- a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java +++ b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java @@ -39,6 +39,7 @@ import javax.annotation.Nullable; import java.io.Serial; import java.io.Serializable; +import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -293,7 +294,15 @@ public Action> createAction( @Override public List createConcentration(final Object descriptor) { - return createConcentration(); + if (descriptor == null) { + return createConcentration(); + } + if (descriptor instanceof final Collection descriptorList) { + return descriptorList.stream().map(it -> + it instanceof final ILsaMolecule lsa ? lsa : createMolecule(it.toString()) + ).toList(); + } + return List.of(createMolecule(descriptor.toString())); } @Override From 11205f638630a0fbafd2d6c43917eb8f9700f664 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 12 Feb 2026 11:15:36 +0100 Subject: [PATCH 182/196] feat: fix regex pattern in SAPEREIncarnation to correctly match nested braces --- .../unibo/alchemist/model/incarnations/SAPEREIncarnation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java index 23f5e886b1..696d465206 100644 --- a/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java +++ b/alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/incarnations/SAPEREIncarnation.java @@ -73,7 +73,7 @@ public final class SAPEREIncarnation

> final String matchStart = "(?:\\s*(?<"; final String condition = matchStart + CONDITION_GROUP + ">\\+"; final String action = matchStart + ACTION_GROUP + ">[+*]"; - final String matchEnd = "?\\{[^\\{\\}]+?\\}))"; + final String matchEnd = "?\\{[^{}]+?}))"; MATCH_CONDITION = Pattern.compile(condition + matchEnd); MATCH_ACTION = Pattern.compile(action + matchEnd); final String sequence = matchEnd + "*\\s*"; From 7995b1e03dbb83fd6e4447e96eb34b273922dd74 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Thu, 12 Feb 2026 11:17:26 +0100 Subject: [PATCH 183/196] docs: update dokka version to 2.2.0-Beta --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f81de57a6b..6ce2e46119 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,7 @@ antlr4 = "4.13.2" apollo ="4.0.0-beta.7" arrow = "2.2.1.1" compose-multiplatform = "1.10.0" -dokka = "2.1.0" +dokka = "2.2.0-Beta" graphql = "9.0.0-alpha.8" graphhopper = "11.0" graphstream = "2.0" From 9a235ddd080d40e90e6799386313b9498406934f Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sat, 14 Feb 2026 22:19:56 +0100 Subject: [PATCH 184/196] chore: move ArbitraryVariable, Flag, LinearVariable, and NumericConstant to Kotlin --- .../it/unibo/alchemist/boundary/Variable.java | 47 ------------ .../boundary/variables/ArbitraryVariable.java | 65 ----------------- .../alchemist/boundary/variables/Flag.java | 44 ------------ .../boundary/variables/GeometricVariable.java | 19 ++++- .../boundary/variables/LinearVariable.java | 71 ------------------- .../boundary/variables/NumericConstant.java | 38 ---------- .../alchemist/boundary/kotlindsl/DSLLoader.kt | 16 +++-- .../boundary/variables/ArbitraryVariable.kt | 56 +++++++++++++++ .../alchemist/boundary/variables/Flag.kt | 32 +++++++++ .../boundary/variables/LinearVariable.kt | 56 +++++++++++++++ .../boundary/variables/NumericConstant.kt | 31 ++++++++ .../synthetic/convoluted_variables.yml | 2 +- 12 files changed, 204 insertions(+), 273 deletions(-) delete mode 100644 alchemist-loading/src/main/java/it/unibo/alchemist/boundary/Variable.java delete mode 100644 alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/ArbitraryVariable.java delete mode 100644 alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/Flag.java delete mode 100644 alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/LinearVariable.java delete mode 100644 alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/NumericConstant.java create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/ArbitraryVariable.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/Flag.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/LinearVariable.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/NumericConstant.kt diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/Variable.java b/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/Variable.java deleted file mode 100644 index dcb1774bd5..0000000000 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/Variable.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary; - -import javax.annotation.Nonnull; -import java.io.Serializable; -import java.util.Iterator; -import java.util.stream.Stream; - -/** - * A variable simulation value that provides a range of values for batches, and - * a default value for single-shot runs. - * - * @param value typ of the variable - */ -public interface Variable extends Serializable, Iterable { - - @Nonnull - @Override - default Iterator iterator() { - return stream().iterator(); - } - - /** - * @return the number of different values this {@link Variable} may yield - */ - default long steps() { - return stream().count(); - } - - /** - * @return the default value for this {@link Variable} - */ - V getDefault(); - - /** - * @return all values of this variable as {@link Stream}. - */ - Stream stream(); -} diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/ArbitraryVariable.java b/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/ArbitraryVariable.java deleted file mode 100644 index b07094672d..0000000000 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/ArbitraryVariable.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2010-2023, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.variables; - -import org.apache.commons.lang3.ArrayUtils; -import org.danilopianini.util.ImmutableListSet; -import org.danilopianini.util.ListSet; - -import java.io.Serial; -import java.io.Serializable; -import java.util.stream.Stream; - -/** - * A variable spanning over an arbitrary set of values. - */ -public final class ArbitraryVariable extends AbstractPrintableVariable { - - @Serial - private static final long serialVersionUID = 1L; - private final Serializable def; - private final ListSet vals; - - private ArbitraryVariable(final ListSet values, final Serializable def) { - this.def = def; - vals = values; - } - - /** - * @param def - * the default value - * @param values - * all the values this variable may yield - */ - public ArbitraryVariable(final Serializable def, final double... values) { - this(ImmutableListSet.of(ArrayUtils.toObject(values)), def); - } - - /** - * @param def - * the default value - * @param values - * all the values this variable may yield - */ - public ArbitraryVariable(final Serializable def, final Iterable values) { - this(ImmutableListSet.copyOf(values), def); - } - - @Override - public Serializable getDefault() { - return def; - } - - @Override - public Stream stream() { - return vals.stream().map(it -> (Serializable) it); - } - -} diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/Flag.java b/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/Flag.java deleted file mode 100644 index 67a482b6d5..0000000000 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/Flag.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2010-2023, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.variables; - -import java.io.Serial; -import java.util.stream.Stream; - -/** - * This variable is a flag. Being booleans not a valid data type in charts, this - * variable just outputs 0 and 1. This is equivalent to a {@link LinearVariable} - * with two samples ranging from 0 to 1. - */ -public final class Flag extends AbstractPrintableVariable { - - @Serial - private static final long serialVersionUID = 1L; - private final boolean defVal; - - /** - * @param def - * the default value - */ - public Flag(final boolean def) { - this.defVal = def; - } - - @Override - public Boolean getDefault() { - return defVal; - } - - @Override - public Stream stream() { - return Stream.of(true, false); - } - -} diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/GeometricVariable.java b/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/GeometricVariable.java index 0293e2cccf..db83aaa7fa 100644 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/GeometricVariable.java +++ b/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/GeometricVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -11,7 +11,9 @@ import org.apache.commons.math3.util.FastMath; +import javax.annotation.Nonnull; import java.io.Serial; +import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -72,7 +74,7 @@ public Double getDefault() { } @Override - public Stream stream() { + public @Nonnull Stream stream() { return IntStream.range(0, maxSamples) .mapToDouble(s -> min * FastMath.pow(max / min, (double) s / Math.max(1, maxSamples - 1))) .boxed(); @@ -83,4 +85,17 @@ public String toString() { return '[' + stream().map(Object::toString).collect(Collectors.joining(",")) + ']'; } + @Override + public boolean equals(final Object obj) { + return obj instanceof final GeometricVariable other + && def == other.def + && maxSamples == other.maxSamples + && min == other.min + && max == other.max; + } + + @Override + public int hashCode() { + return Objects.hash(def, min, max, maxSamples); + } } diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/LinearVariable.java b/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/LinearVariable.java deleted file mode 100644 index 07ed8f1926..0000000000 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/LinearVariable.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2010-2023, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.variables; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.Serial; -import java.util.stream.DoubleStream; -import java.util.stream.Stream; - -/** - * This class represents a linear variable, namely a variable whose values span - * linearly between minimum and maximum. - */ -public final class LinearVariable extends AbstractPrintableVariable { - - @Serial - private static final long serialVersionUID = 2462199794377640948L; - private static final Logger L = LoggerFactory.getLogger(LinearVariable.class); - private final double min; - private final double max; - private final double step; - private final double def; - - /** - * @param def default value - * @param min minimum (inclusive) - * @param max maximum (inclusive) - * @param step number of steps - */ - public LinearVariable(final double def, final double min, final double max, final double step) { - if (max < min) { - throw new IllegalArgumentException("The maximum value is smaller than the minimum."); - } - if (def > max || def < min) { - L.warn("The provided default value for a linear variable ({}) is out of bounds: [{}, {}]", def, min, max); - } - this.min = min; - this.max = max; - this.step = step; - this.def = def; - } - - @Override - public Double getDefault() { - return def; - } - - @Override - public long steps() { - final long num = (long) Math.ceil((max - min) / step); - if (min + step * num <= max) { - return num + 1; - } - return num; - } - - @Override - public Stream stream() { - return DoubleStream.iterate(min, x -> x + step).limit(steps()).boxed(); - } - -} diff --git a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/NumericConstant.java b/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/NumericConstant.java deleted file mode 100644 index 567d409516..0000000000 --- a/alchemist-loading/src/main/java/it/unibo/alchemist/boundary/variables/NumericConstant.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2010-2023, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.variables; - -import it.unibo.alchemist.boundary.DependentVariable; - -import java.io.Serial; -import java.util.Map; - -/** - * A numeric constant. - */ -public final class NumericConstant implements DependentVariable { - - @Serial - private static final long serialVersionUID = 1L; - private final Number internal; - - /** - * @param n the number - */ - public NumericConstant(final Number n) { - internal = n; - } - - @Override - public Number getWith(final Map variables) { - return internal; - } - -} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt index eccad4af2a..0417987a77 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt @@ -137,14 +137,20 @@ internal class DSLLoader, I : Incarnation>( override fun variable(variable: Variable) = VariableDelegateFactory { _, property -> - check(property.name !in variables.keys) { - "Error: variable '${property.name}' defined multiple times. " + - "The first definition binds to: ${variables[property.name]}" + var registeredVariable = variables[property.name] + if (registeredVariable == null) { + logger.debug("Registering variable '{}' with definition: {}", property.name, variable) + variables += property.name to variable + registeredVariable = variable + } + check(registeredVariable == variable) { + "Error: variable '${property.name}' was defined multiple times. " + + "The first definition binds to: $registeredVariable, " + + "while the second definition attempts to bind to: $variable." } - variables += property.name to variable ReadOnlyProperty { _, _ -> @Suppress("UNCHECKED_CAST") - values.getOrDefault(property.name, variable.default) as V + values.getOrDefault(property.name, registeredVariable.default) as V } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/ArbitraryVariable.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/ArbitraryVariable.kt new file mode 100644 index 0000000000..607eca7fb1 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/ArbitraryVariable.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +package it.unibo.alchemist.boundary.variables + +import java.io.Serial +import java.io.Serializable + +/** + * A variable that can take any value from an arbitrary, finite set. + * + * This implementation stores values in an immutable ordered set. Values and + * the default are non-nullable: an [ArbitraryVariable] always contains at + * least a default value and a (possibly empty) set of candidate values. + * + * @property values the set of allowed values (non-nullable) + * @property default the default value (non-nullable) + */ +data class ArbitraryVariable(override val default: Serializable, private val values: List) : + AbstractPrintableVariable() { + + init { + require(values.distinct() == values) { + "Values must be distinct: found duplicates in $values" + } + } + + /** + * Convenience constructor: build from a default value and a vararg of doubles. + * @param default the default value + * @param values values to include in the set + */ + constructor(default: Serializable, vararg values: Double) : this( + default, + values.toList(), + ) + + /** + * Construct from a default value and any iterable collection of values. + * @param default the default value + * @param values iterable containing the allowed values + */ + constructor(default: Serializable, values: Iterable) : this(default, values.toList()) + + override fun stream() = values.stream() + + private companion object { + @Serial + private const val serialVersionUID = 1L + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/Flag.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/Flag.kt new file mode 100644 index 0000000000..8223f5e35c --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/Flag.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ +package it.unibo.alchemist.boundary.variables + +import java.io.Serial +import java.util.stream.Stream + +/** + * A boolean flag variable. Charts typically accept numeric values, but the + * semantic value of this variable is boolean; use `true` and `false` as the + * two possible outputs. The default value is provided at construction. + * + * This is equivalent in behavior to a [LinearVariable] with two samples + * between 0 and 1, but keeps the boolean semantics. + * + * @param default the default boolean value + */ +data class Flag(override val default: Boolean) : AbstractPrintableVariable() { + + override fun stream(): Stream = Stream.of(true, false) + + private companion object { + @Serial + private const val serialVersionUID = 1L + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/LinearVariable.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/LinearVariable.kt new file mode 100644 index 0000000000..bb2fa26d87 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/LinearVariable.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.variables + +import java.util.stream.DoubleStream +import java.util.stream.Stream +import kotlin.math.ceil +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +/** + * A variable that spans linearly between a minimum and a maximum value. + * + * This is represented as a sequence of values starting at [min], incrementing by + * [step], and not exceeding [max]. The [default] parameter is the default value for + * the variable (it is not constrained to be exactly one of the generated steps). + * + * Note: kept as a data class for convenient structural equality and debugging; + * the implementation preserves the original behavior of the prior class. + * + * @property default default value + * @property min minimum value (inclusive) + * @property max maximum value (inclusive) + * @property step step increment between successive values + */ +data class LinearVariable(override val default: Double, val min: Double, val max: Double, val step: Double) : + AbstractPrintableVariable() { + + init { + require(max > min) { "The maximum value is smaller than the minimum in $this." } + if (default !in min..max) { + LOGGER.warn("Default value {} of linear variable is out of bounds: [{}, {}]", default, min, max) + } + } + + override fun steps(): Long { + val steps = ceil((max - min) / step).toLong() + if (min + step * steps <= max) { + return steps + 1 + } + return steps + } + + override fun stream(): Stream = DoubleStream.iterate(min) { x: Double -> x + step }.limit(steps()).boxed() + + private companion object { + private val LOGGER: Logger = LoggerFactory.getLogger(LinearVariable::class.java) + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/NumericConstant.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/NumericConstant.kt new file mode 100644 index 0000000000..52db864058 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/NumericConstant.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.variables + +import it.unibo.alchemist.boundary.DependentVariable +import java.io.Serial + +/** + * A numeric constant variable that always evaluates to the same [value]. + * + * This class is a lightweight implementation of [DependentVariable] that + * represents a fixed numeric value. Nullability has been removed: a + * numeric constant must hold a non-null [Number]. + * + * @param value the numeric value returned by this variable + */ +data class NumericConstant(val value: Number) : DependentVariable { + override fun getWith(variables: Map): Number = value + + private companion object { + @Serial + private const val serialVersionUID = 1L + } +} diff --git a/alchemist-loading/src/test/resources/synthetic/convoluted_variables.yml b/alchemist-loading/src/test/resources/synthetic/convoluted_variables.yml index 5cce51e942..11f00f56f1 100644 --- a/alchemist-loading/src/test/resources/synthetic/convoluted_variables.yml +++ b/alchemist-loading/src/test/resources/synthetic/convoluted_variables.yml @@ -12,7 +12,7 @@ variables: default: 0 speed: &speed type: ArbitraryVariable - parameters: [0.1, [0.1, 0.1, 1]] + parameters: [0.1, [0.1, 0.11, 1]] latencies: formula: "[0.001, 0.01, 0.1, 1]" tolerances: From b5752f0343bb81125c9d57c9e3ac3e30d6fc3791 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sat, 14 Feb 2026 22:40:42 +0100 Subject: [PATCH 185/196] feat: update formulas in null bindings and add Variable interface --- .../it/unibo/alchemist/boundary/Variable.kt | 43 +++++++++++++++++++ .../it/unibo/alchemist/test/TestKtVariable.kt | 6 +-- .../2022-coordination-null-bindings.yml | 6 +-- 3 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Variable.kt diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Variable.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Variable.kt new file mode 100644 index 0000000000..b3afbcfe20 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Variable.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary + +import java.io.Serializable +import java.util.stream.Stream +import javax.annotation.Nonnull + +/** + * A variable simulation value that provides a range of values for batches, and + * a default value for single-shot runs. + * + * @param value typ of the variable + */ +interface Variable : + Serializable, + Iterable { + + @Nonnull + override fun iterator(): MutableIterator = stream().iterator() + + /** + * @return the number of different values this [Variable] may yield + */ + fun steps(): Long = stream().count() + + /** + * @return the default value for this [Variable] + */ + val default: V + + /** + * @return all values of this variable as [java.util.stream.Stream]. + */ + fun stream(): Stream +} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/test/TestKtVariable.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/test/TestKtVariable.kt index 9c7e97a679..d44752a1bf 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/test/TestKtVariable.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/test/TestKtVariable.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -57,13 +57,13 @@ class TestKtVariable> : "test 'type' keyword clashes" { loadAlchemistFromResource("regression/2022-coordination-type-clash.yml") shouldNot beNull() } - "test null values in bindings" { + "dependent variables should support null values" { val simulation = loadAlchemistFromResource("regression/2022-coordination-null-bindings.yml") simulation shouldNot beNull() val variable = simulation.variables["result"] variable shouldNot beNull() val values = variable?.toList().orEmpty() - values.forEach { it shouldBe "null" } + values.forEach { it.toString().substringBefore(" ") shouldBe "null" } } // This is a regression test, when the simulation is loaded with formula defined inside a "seed" definition diff --git a/alchemist-loading/src/test/resources/regression/2022-coordination-null-bindings.yml b/alchemist-loading/src/test/resources/regression/2022-coordination-null-bindings.yml index 56253e7ebb..566d79cf04 100644 --- a/alchemist-loading/src/test/resources/regression/2022-coordination-null-bindings.yml +++ b/alchemist-loading/src/test/resources/regression/2022-coordination-null-bindings.yml @@ -6,13 +6,13 @@ variables: kotlin: &k language: kotlin # Once bugged due to: https://youtrack.jetbrains.com/issue/KT-51213 - formula: base.toString() + formula: base.toString() + " kotlin" groovy: &g language: groovy - formula: base.toString() + formula: base.toString() + " groovy" scala: &s language: scala - formula: if (base == null) "null" else base.toString() + formula: (if (base == null) "null" else base.toString()) + " scala" result: type: ArbitraryVariable parameters: [*k, [*g, *s, *k]] From 8f01dd4f06c98eda67ad409bab62cc0d4249e4fb Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sat, 14 Feb 2026 22:49:17 +0100 Subject: [PATCH 186/196] feat: update DSL script to use simulation2D and improve environment structure --- .../boundary/kotlindsl/KotlinDslProviderTest.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt index c41e4e0ab3..81be9495bb 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt @@ -25,11 +25,13 @@ class KotlinDslProviderTest { @Test fun `a simple textual Kotlin DSL script should load`() { val script = """ - simulation(SAPEREIncarnation()) { - networkModel = ConnectWithinDistance(5.0) - deployments { - deploy(point(0.0, 0.0)) - deploy(point(0.0, 1.0)) + simulation2D(SAPEREIncarnation()) { + environment { + networkModel(ConnectWithinDistance(5.0)) + deployments { + deploy(point(0.0, 0.0)) + deploy(point(0.0, 1.0)) + } } } """.trimIndent() From 0486f16d88b62e697ae92e0ed53bf6cec40e701c Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 15 Feb 2026 00:11:20 +0100 Subject: [PATCH 187/196] midgame save --- alchemist-kotlinscript/build.gradle.kts | 16 ++ .../AlchemistCompilationConfiguration.kt | 43 +---- .../alchemist/kotlinscript/AlchemistScript.kt | 66 ------- .../kotlinscript/AlchemistScriptHost.kt | 43 +++++ alchemist-loading/build.gradle.kts | 4 +- .../boundary/loader/LoadingSystem.kt | 87 ++++----- .../boundary/loader/SimulationModel.kt | 94 +++++----- .../{Syntax.kt => AlchemistYamlSyntax.kt} | 14 +- .../boundary/loader/syntax/OwnName.kt | 16 ++ .../boundary/loader/util/JVMConstructor.kt | 177 +----------------- .../loader/util/NamedParametersConstructor.kt | 140 ++++++++++++++ .../boundary/loader/util/OrderedParameters.kt | 14 ++ .../util/OrderedParametersConstructor.kt | 23 +++ .../boundary/loader/util/TypeSearch.kt | 52 +++++ .../boundary/variables/JSR223Variable.kt | 6 +- .../dsl/kts/11-monitors.alchemist.kts | 8 +- .../resources/dsl/kts/12-layers.alchemist.kts | 48 ++--- .../dsl/kts/14-exporters.alchemist.kts | 25 +-- .../dsl/kts/15-variables.alchemist.kts | 53 ++---- 19 files changed, 463 insertions(+), 466 deletions(-) rename alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistScript.kt => alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistCompilationConfiguration.kt (65%) create mode 100644 alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt rename alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/{Syntax.kt => AlchemistYamlSyntax.kt} (94%) create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/OwnName.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/NamedParametersConstructor.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/OrderedParameters.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/OrderedParametersConstructor.kt create mode 100644 alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/TypeSearch.kt diff --git a/alchemist-kotlinscript/build.gradle.kts b/alchemist-kotlinscript/build.gradle.kts index adf5ea353a..8cb4df2515 100644 --- a/alchemist-kotlinscript/build.gradle.kts +++ b/alchemist-kotlinscript/build.gradle.kts @@ -1,8 +1,24 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +import Libs.alchemist + plugins { id("kotlin-jvm-convention") } dependencies { + rootProject.subprojects.filter { "incarnation" in it.name }.forEach { + implementation(it) + } + implementation(alchemist("cognitive-agents")) + implementation(alchemist("loading")) implementation(kotlin("script-runtime")) implementation(kotlin("scripting-common")) implementation(kotlin("scripting-jvm")) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistScript.kt b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistCompilationConfiguration.kt similarity index 65% rename from alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistScript.kt rename to alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistCompilationConfiguration.kt index 5688b75c4f..fd26729785 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/AlchemistScript.kt +++ b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistCompilationConfiguration.kt @@ -7,9 +7,10 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -package it.unibo.alchemist.boundary.kotlindsl +package it.unibo.alchemist.kotlinscript -import kotlin.script.experimental.annotations.KotlinScript +import it.unibo.alchemist.boundary.kotlindsl.SimulationContext +import it.unibo.alchemist.model.incarnations.ProtelisIncarnation import kotlin.script.experimental.api.ScriptAcceptedLocation import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.api.acceptedLocations @@ -19,28 +20,11 @@ import kotlin.script.experimental.api.ide import kotlin.script.experimental.jvm.dependenciesFromClassContext import kotlin.script.experimental.jvm.jvm -/** - * Base interface for Alchemist Kotlin DSL scripts. - */ -@KotlinScript( - displayName = "Alchemist Kotlin DSL", - fileExtension = "alchemist.kts", - compilationConfiguration = AlchemistCompilationConfiguration::class, -) -interface AlchemistScript - /** * Compilation configuration for Alchemist scripts. */ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ defaultImports( - "it.unibo.alchemist.boundary.kotlindsl.*", - "it.unibo.alchemist.boundary.dsl.Dsl.incarnation", - "it.unibo.alchemist.boundary.dsl.model.AvailableIncarnations.*", - "it.unibo.alchemist.boundary.dsl.model.Incarnation.*", - "it.unibo.alchemist.boundary.dsl.generated.*", - "it.unibo.alchemist.boundary.dsl.*", - "it.unibo.alchemist.boundary.dsl.Dsl.*", "it.unibo.alchemist.model.*", "it.unibo.alchemist.model.deployments.*", "it.unibo.alchemist.model.incarnations.*", @@ -57,40 +41,33 @@ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ "it.unibo.alchemist.model.neighborhoods.*", "it.unibo.alchemist.model.nodes.*", "it.unibo.alchemist.model.positions.*", - "it.unibo.alchemist.model.positionfilters.And", - "it.unibo.alchemist.model.positionfilters.Or", - "it.unibo.alchemist.model.positionfilters.Not", - "it.unibo.alchemist.model.positionfilters.Xor", + "it.unibo.alchemist.model.positionfilters.*", "it.unibo.alchemist.model.properties.*", "it.unibo.alchemist.model.routes.*", "it.unibo.alchemist.model.reactions.*", "it.unibo.alchemist.model.terminators.*", "it.unibo.alchemist.model.timedistributions.*", + "it.unibo.alchemist.model.times.*", "it.unibo.alchemist.boundary.properties.*", - "it.unibo.alchemist.boundary.dsl.aliases.*", "it.unibo.alchemist.boundary.exporters.*", "it.unibo.alchemist.boundary.extractors.*", "it.unibo.alchemist.boundary.launchers.*", "it.unibo.alchemist.boundary.statistic.*", "it.unibo.alchemist.boundary.exportfilters.*", "it.unibo.alchemist.boundary.variables.*", - "it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger", + "it.unibo.alchemist.boundary.kotlindsl.*" ) ide { acceptedLocations(ScriptAcceptedLocation.Everywhere) } jvm { dependenciesFromClassContext(AlchemistScript::class, wholeClasspath = true) + dependenciesFromClassContext(ProtelisIncarnation::class, wholeClasspath = true) + dependenciesFromClassContext(SimulationContext::class, wholeClasspath = true) compilerOptions.append("-Xcontext-parameters") } }) { - /** - * Return the singleton instance on deserialization. - * This is intentionally private and used by Java serialization. Detekt flags it as unused, - * but it is required by the serialization mechanism. - * - * See: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/input.html - */ - @Suppress("unused") + // See: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/input.html + @Suppress("UnusedPrivateFunction") private fun readResolve(): Any = AlchemistCompilationConfiguration } diff --git a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt index 837d1ce55b..26356d2b13 100644 --- a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt +++ b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt @@ -10,14 +10,6 @@ package it.unibo.alchemist.kotlinscript import kotlin.script.experimental.annotations.KotlinScript -import kotlin.script.experimental.api.ScriptAcceptedLocation -import kotlin.script.experimental.api.ScriptCompilationConfiguration -import kotlin.script.experimental.api.acceptedLocations -import kotlin.script.experimental.api.compilerOptions -import kotlin.script.experimental.api.defaultImports -import kotlin.script.experimental.api.ide -import kotlin.script.experimental.jvm.dependenciesFromClassContext -import kotlin.script.experimental.jvm.jvm /** * Base interface for Alchemist Kotlin DSL scripts. @@ -29,61 +21,3 @@ import kotlin.script.experimental.jvm.jvm ) interface AlchemistScript -/** - * Compilation configuration for Alchemist scripts. - */ -object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ - defaultImports( - "it.unibo.alchemist.boundary.dsl.Dsl.simulation", - "it.unibo.alchemist.boundary.dsl.generated.*", - "it.unibo.alchemist.boundary.dsl.*", - "it.unibo.alchemist.boundary.dsl.Dsl.*", - "it.unibo.alchemist.model.*", - "it.unibo.alchemist.model.deployments.*", - "it.unibo.alchemist.model.incarnations.*", - "it.unibo.alchemist.model.actions.*", - "it.unibo.alchemist.model.conditions.*", - "it.unibo.alchemist.model.environments.*", - "it.unibo.alchemist.model.geometry.*", - "it.unibo.alchemist.model.layers.*", - "it.unibo.alchemist.model.linkingrules.*", - "it.unibo.alchemist.model.maps.actions.*", - "it.unibo.alchemist.model.maps.deployments.*", - "it.unibo.alchemist.model.maps.environments.*", - "it.unibo.alchemist.model.movestrategies.*", - "it.unibo.alchemist.model.neighborhoods.*", - "it.unibo.alchemist.model.nodes.*", - "it.unibo.alchemist.model.positions.*", - "it.unibo.alchemist.model.positionfilters.And", - "it.unibo.alchemist.model.positionfilters.Or", - "it.unibo.alchemist.model.positionfilters.Not", - "it.unibo.alchemist.model.positionfilters.Xor", - "it.unibo.alchemist.model.positionfilters.*", - "it.unibo.alchemist.model.properties.*", - "it.unibo.alchemist.model.routes.*", - "it.unibo.alchemist.model.reactions.*", - "it.unibo.alchemist.model.terminators.*", - "it.unibo.alchemist.model.timedistributions.*", - "it.unibo.alchemist.model.times.*", - "it.unibo.alchemist.boundary.properties.*", - "it.unibo.alchemist.boundary.dsl.aliases.*", - "it.unibo.alchemist.boundary.exporters.*", - "it.unibo.alchemist.boundary.extractors.*", - "it.unibo.alchemist.boundary.launchers.*", - "it.unibo.alchemist.boundary.statistic.*", - "it.unibo.alchemist.boundary.exportfilters.*", - "it.unibo.alchemist.boundary.variables.*", - "it.unibo.alchemist.boundary.dsl.util.LoadingSystemLogger.logger", - ) - ide { - acceptedLocations(ScriptAcceptedLocation.Everywhere) - } - jvm { - dependenciesFromClassContext(AlchemistScript::class, wholeClasspath = true) - compilerOptions.append("-Xcontext-parameters") - } -}) { - // See: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/input.html - @Suppress("UnusedPrivateFunction") - private fun readResolve(): Any = AlchemistCompilationConfiguration -} diff --git a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt new file mode 100644 index 0000000000..6be56a0ba1 --- /dev/null +++ b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.kotlinscript + +import it.unibo.alchemist.boundary.Loader +import java.io.File +import kotlin.script.experimental.api.ResultValue +import kotlin.script.experimental.api.ScriptDiagnostic +import kotlin.script.experimental.api.ScriptEvaluationConfiguration +import kotlin.script.experimental.api.valueOrNull +import kotlin.script.experimental.host.toScriptSource +import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost + +fun main(vararg args: String) { + require(args.size == 1) { "usage: " } + + val scriptFile = File(args[0]) + val result = BasicJvmScriptingHost().eval( + scriptFile.toScriptSource(), + AlchemistCompilationConfiguration, + ScriptEvaluationConfiguration { +// jvm { mainArguments(scriptArgs) } + } + ) + + result.reports + .filter { it.severity > ScriptDiagnostic.Severity.DEBUG } + .forEach { d -> System.err.println("${d.severity}: ${d.message}") } + + val eval = result.valueOrNull() + val returned = (eval?.returnValue as? ResultValue.Value)?.value + check(returned is Loader) { + "The script should return a Loader, but it returned ${returned?.javaClass ?: "nothing"}" + } + returned.launcher.launch(returned) +} diff --git a/alchemist-loading/build.gradle.kts b/alchemist-loading/build.gradle.kts index 3cf55189d9..b3077f26e2 100644 --- a/alchemist-loading/build.gradle.kts +++ b/alchemist-loading/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -22,7 +22,6 @@ dependencies { implementation(alchemist("engine")) implementation(alchemist("euclidean-geometry")) - implementation(alchemist("kotlinscript")) implementation(kotlin("reflect")) implementation(kotlin("script-runtime")) implementation(kotlin("scripting-common")) @@ -47,6 +46,7 @@ dependencies { runtimeOnly(libs.scala.compiler) testImplementation(alchemist("engine")) + testImplementation(alchemist("kotlinscript")) testImplementation(alchemist("maps")) testImplementation(alchemist("test")) testImplementation(incarnation("sapere")) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/LoadingSystem.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/LoadingSystem.kt index cb079c2bcc..9cd67fac25 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/LoadingSystem.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/LoadingSystem.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -13,7 +13,7 @@ import it.unibo.alchemist.boundary.Exporter import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.boundary.exporters.GlobalExporter import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger -import it.unibo.alchemist.boundary.loader.syntax.DocumentRoot +import it.unibo.alchemist.boundary.loader.syntax.AlchemistYamlSyntax import it.unibo.alchemist.core.Engine import it.unibo.alchemist.core.Simulation import it.unibo.alchemist.model.Deployment @@ -70,23 +70,23 @@ internal abstract class LoadingSystem(private val originalContext: Context, priv root = SimulationModel.inject(context, root) logger.debug("Complete simulation model: {}", root) // SEEDS - val (scenarioRNG, simulationRNG) = SimulationModel.visitSeeds(context, root[DocumentRoot.seeds]) + val (scenarioRNG, simulationRNG) = SimulationModel.visitSeeds(context, root[AlchemistYamlSyntax.seeds]) setCurrentRandomGenerator(simulationRNG) // INCARNATION - val incarnation = SimulationModel.visitIncarnation(root[DocumentRoot.incarnation]) + val incarnation = SimulationModel.visitIncarnation(root[AlchemistYamlSyntax.incarnation]) contextualize(incarnation) registerImplicit(incarnation::createMolecule) registerImplicit(incarnation::createConcentration) // ENVIRONMENT val environment: Environment = - SimulationModel.visitEnvironment(incarnation, context, root[DocumentRoot.environment]) + SimulationModel.visitEnvironment(incarnation, context, root[AlchemistYamlSyntax.environment]) logger.info("Created environment: {}", environment) contextualize(environment) // GLOBAL PROGRAMS loadGlobalProgramsOnEnvironment(simulationRNG, incarnation, environment, root) // LAYERS val layers: List>> = - SimulationModel.visitLayers(incarnation, context, root[DocumentRoot.layers]) + SimulationModel.visitLayers(incarnation, context, root[AlchemistYamlSyntax.layers]) layers .groupBy { it.first } .mapValues { (_, pair) -> pair.map { it.second } } @@ -101,19 +101,19 @@ internal abstract class LoadingSystem(private val originalContext: Context, priv } // LINKING RULE val linkingRule = - SimulationModel.visitLinkingRule(context, root.getOrEmptyMap(DocumentRoot.LINKING_RULES)) + SimulationModel.visitLinkingRule(context, root.getOrEmptyMap(AlchemistYamlSyntax.LINKING_RULES)) environment.linkingRule = linkingRule contextualize(linkingRule) // MONITORS - val monitors = SimulationModel.visitOutputMonitors(context, root[DocumentRoot.monitors]) + val monitors = SimulationModel.visitOutputMonitors(context, root[AlchemistYamlSyntax.monitors]) // DEPLOYMENTS setCurrentRandomGenerator(scenarioRNG) - val displacementsSource = root.getOrEmpty(DocumentRoot.deployments) + val displacementsSource = root.getOrEmpty(AlchemistYamlSyntax.deployments) val deploymentDescriptors: List> = SimulationModel.visitRecursively( context, displacementsSource, - syntax = DocumentRoot.Deployment, + syntax = AlchemistYamlSyntax.Deployment, ) { element -> (element as? Map<*, *>)?.let { _ -> setCurrentRandomGenerator(scenarioRNG) @@ -124,10 +124,12 @@ internal abstract class LoadingSystem(private val originalContext: Context, priv } } setCurrentRandomGenerator(simulationRNG) - val terminators: List> = - SimulationModel.visitRecursively(context, root.getOrEmpty(DocumentRoot.terminate)) { terminator -> - (terminator as? Map<*, *>)?.let { SimulationModel.visitBuilding(context, it) } - } + val terminators: List> = SimulationModel.visitRecursively( + context, + root.getOrEmpty(AlchemistYamlSyntax.terminate), + ) { terminator -> + (terminator as? Map<*, *>)?.let { SimulationModel.visitBuilding(context, it) } + } terminators.forEach(environment::addTerminator) if (deploymentDescriptors.isEmpty()) { logger.warn("There are no displacements in the specification, the environment won't have any node") @@ -138,13 +140,13 @@ internal abstract class LoadingSystem(private val originalContext: Context, priv val exporters = SimulationModel.visitRecursively>( context, - root.getOrEmpty(DocumentRoot.export), + root.getOrEmpty(AlchemistYamlSyntax.export), ) { SimulationModel.visitSingleExporter(incarnation, context, it) } exporters.forEach { it.bindVariables(variableValues) } // ENGINE - val engineDescriptor = root[DocumentRoot.engine] + val engineDescriptor = root[AlchemistYamlSyntax.engine] val engine: Simulation = SimulationModel .visitBuilding>(context, engineDescriptor) @@ -165,29 +167,30 @@ internal abstract class LoadingSystem(private val originalContext: Context, priv environment: Environment, descriptor: Map<*, *>, ) { - val environmentDescriptor = descriptor[DocumentRoot.environment] + val environmentDescriptor = descriptor[AlchemistYamlSyntax.environment] if (environmentDescriptor is Map<*, *>) { - val programDescriptor = environmentDescriptor.getOrEmpty(DocumentRoot.Environment.GLOBAL_PROGRAMS) - val globalPrograms = - SimulationModel.visitRecursively( - context, - programDescriptor, - DocumentRoot.Environment.GlobalProgram, - ) { program -> - requireNotNull(program) { - "null is not a valid program in $descriptor." + - DocumentRoot.Environment.GlobalProgram.guide - } - (program as? Map<*, *>)?.let { - SimulationModel - .visitProgram(randomGenerator, incarnation, environment, null, context, it) - ?.onSuccess { (_, actionable) -> - if (actionable is GlobalReaction) { - environment.addGlobalReaction(actionable) - } + val programDescriptor = environmentDescriptor.getOrEmpty( + AlchemistYamlSyntax.Environment.GLOBAL_PROGRAMS, + ) + val globalPrograms = SimulationModel.visitRecursively( + context, + programDescriptor, + AlchemistYamlSyntax.Environment.GlobalProgram, + ) { program -> + requireNotNull(program) { + "null is not a valid program in $descriptor." + + AlchemistYamlSyntax.Environment.GlobalProgram.guide + } + (program as? Map<*, *>)?.let { + SimulationModel + .visitProgram(randomGenerator, incarnation, environment, null, context, it) + ?.onSuccess { (_, actionable) -> + if (actionable is GlobalReaction) { + environment.addGlobalReaction(actionable) } - } + } } + } logger.debug("Global programs: {}", globalPrograms) } } @@ -224,15 +227,15 @@ internal abstract class LoadingSystem(private val originalContext: Context, priv nodePosition: P, descriptor: Map<*, *>, ) { - val programDescriptor = descriptor.getOrEmpty(DocumentRoot.Deployment.programs) + val programDescriptor = descriptor.getOrEmpty(AlchemistYamlSyntax.Deployment.programs) val programs = SimulationModel.visitRecursively( context, programDescriptor, - DocumentRoot.Deployment.Program, + AlchemistYamlSyntax.Deployment.Program, ) { program -> requireNotNull(program) { - "null is not a valid program in $descriptor. ${DocumentRoot.Deployment.Program.guide}" + "null is not a valid program in $descriptor. ${AlchemistYamlSyntax.Deployment.Program.guide}" } (program as? Map<*, *>)?.let { SimulationModel @@ -258,11 +261,11 @@ internal abstract class LoadingSystem(private val originalContext: Context, priv descriptor: Map<*, *>, ) { logger.debug("Processing deployment: {} with descriptor: {}", deployment, descriptor) - val nodeDescriptor = descriptor[DocumentRoot.Deployment.nodes] - if (descriptor.containsKey(DocumentRoot.Deployment.nodes)) { + val nodeDescriptor = descriptor[AlchemistYamlSyntax.Deployment.nodes] + if (descriptor.containsKey(AlchemistYamlSyntax.Deployment.nodes)) { requireNotNull(nodeDescriptor) { "Invalid node type descriptor: $nodeDescriptor" } if (nodeDescriptor is Map<*, *>) { - DocumentRoot.JavaType.validateDescriptor(nodeDescriptor) + AlchemistYamlSyntax.JavaType.validateDescriptor(nodeDescriptor) } } // ADDITIONAL LINKING RULES diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt index 7b43e2d1f1..59f178f6dd 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt @@ -23,14 +23,14 @@ import it.unibo.alchemist.boundary.extractors.MoleculeReader import it.unibo.alchemist.boundary.extractors.Time import it.unibo.alchemist.boundary.launchers.DefaultLauncher import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger -import it.unibo.alchemist.boundary.loader.syntax.DocumentRoot -import it.unibo.alchemist.boundary.loader.syntax.DocumentRoot.DependentVariable.formula as formulaKey -import it.unibo.alchemist.boundary.loader.syntax.DocumentRoot.DependentVariable.language as languageKey -import it.unibo.alchemist.boundary.loader.syntax.DocumentRoot.DependentVariable.timeout as timeoutKey -import it.unibo.alchemist.boundary.loader.syntax.DocumentRoot.Deployment.Program as ProgramSyntax -import it.unibo.alchemist.boundary.loader.syntax.DocumentRoot.Environment.GlobalProgram as GlobalProgramSyntax -import it.unibo.alchemist.boundary.loader.syntax.DocumentRoot.JavaType -import it.unibo.alchemist.boundary.loader.syntax.DocumentRoot.Layer as LayerSyntax +import it.unibo.alchemist.boundary.loader.syntax.AlchemistYamlSyntax +import it.unibo.alchemist.boundary.loader.syntax.AlchemistYamlSyntax.DependentVariable.formula as formulaKey +import it.unibo.alchemist.boundary.loader.syntax.AlchemistYamlSyntax.DependentVariable.language as languageKey +import it.unibo.alchemist.boundary.loader.syntax.AlchemistYamlSyntax.DependentVariable.timeout as timeoutKey +import it.unibo.alchemist.boundary.loader.syntax.AlchemistYamlSyntax.Deployment.Program as ProgramSyntax +import it.unibo.alchemist.boundary.loader.syntax.AlchemistYamlSyntax.Environment.GlobalProgram as GlobalProgramSyntax +import it.unibo.alchemist.boundary.loader.syntax.AlchemistYamlSyntax.JavaType +import it.unibo.alchemist.boundary.loader.syntax.AlchemistYamlSyntax.Layer as LayerSyntax import it.unibo.alchemist.boundary.loader.syntax.SyntaxElement import it.unibo.alchemist.boundary.loader.util.JVMConstructor import it.unibo.alchemist.boundary.loader.util.NamedParametersConstructor @@ -123,7 +123,7 @@ private fun Any?.removeKeysRecursively(keys: Set): Any? = when (this) { is String -> this is Map<*, *> -> { val isAnObjectToBuild = - listOf(JavaType, DocumentRoot.DependentVariable, DocumentRoot.Variable) + listOf(JavaType, AlchemistYamlSyntax.DependentVariable, AlchemistYamlSyntax.Variable) .any { it.validateDescriptor(this) } when { isAnObjectToBuild -> this @@ -176,8 +176,8 @@ internal object SimulationModel { * Converts an alchemist model defined as a Map into a loadable simulation environment and relative exports. */ fun fromMap(root: Map): Loader { - require(DocumentRoot.validateDescriptor(root)) { - "Invalid simulation descriptor: $root.\n" + DocumentRoot.validDescriptors.first() + require(AlchemistYamlSyntax.validateDescriptor(root)) { + "Invalid simulation descriptor: $root.\n" + AlchemistYamlSyntax.validDescriptors.first() } val context = Context() var previousSize: Int? = null @@ -185,11 +185,11 @@ internal object SimulationModel { val collectedNonFatalFailures = mutableMapOf>() while (context.constants.size != previousSize) { previousSize = context.constants.size - val stillToTry = injectedRoot[DocumentRoot.variables]?.removeKeysRecursively(context.constants.keys) + val stillToTry = injectedRoot[AlchemistYamlSyntax.variables]?.removeKeysRecursively(context.constants.keys) visitNamedRecursively( context = context, root = stillToTry ?: emptyMap(), - syntax = DocumentRoot.DependentVariable, + syntax = AlchemistYamlSyntax.DependentVariable, forceSuccess = false, ) { name, element -> val evaluationAsConstant = visitConstant(name, context, element) @@ -209,13 +209,13 @@ internal object SimulationModel { } logger.info("{} constants: {}", context.constants.size, context.constants) val constantsNames = context.constants.keys - val varsWithoutConsts = injectedRoot[DocumentRoot.variables].removeKeysRecursively(constantsNames) + val varsWithoutConsts = injectedRoot[AlchemistYamlSyntax.variables].removeKeysRecursively(constantsNames) // Dependent variables val dependentVariables: Map> = visitNamedRecursively( context = context, root = varsWithoutConsts, - syntax = DocumentRoot.DependentVariable, + syntax = AlchemistYamlSyntax.DependentVariable, forceSuccess = false, ) { name, element -> visitDependentVariableRegistering(name, context, element) @@ -224,11 +224,11 @@ internal object SimulationModel { injectedRoot = inject(context, injectedRoot) // Real variables val variablesLeft = - injectedRoot[DocumentRoot.variables].removeKeysRecursively(constantsNames + dependentVariables.keys) + injectedRoot[AlchemistYamlSyntax.variables].removeKeysRecursively(constantsNames + dependentVariables.keys) variablesLeft?.validateVariableConsistencyRecursively(errors = collectedNonFatalFailures) val variables: Map> = visitVariables(context, variablesLeft) logger.info("Variables: {}", variables) - var launcherDescriptor = injectedRoot[DocumentRoot.launcher] + var launcherDescriptor = injectedRoot[AlchemistYamlSyntax.launcher] val isJvmConstructorWithoutType = launcherDescriptor is Map<*, *> && launcherDescriptor.containsKey(JavaType.parameters) && @@ -241,7 +241,7 @@ internal object SimulationModel { val remoteDependencies = visitRecursively( context, - injectedRoot[DocumentRoot.REMOTE_DEPENDENCIES] ?: emptyMap(), + injectedRoot[AlchemistYamlSyntax.REMOTE_DEPENDENCIES] ?: emptyMap(), ) { visitBuilding(context, it) } logger.info("Remote dependencies: {}", remoteDependencies) return object : LoadingSystem(context, injectedRoot) { @@ -410,7 +410,7 @@ internal object SimulationModel { } private fun

> visitFilter(context: Context, element: Map<*, *>): List> { - val filterKey = DocumentRoot.Deployment.Filter.FILTER + val filterKey = AlchemistYamlSyntax.Deployment.Filter.FILTER val positionBasedFilters = visitRecursively(context, element[filterKey] ?: emptyList()) { shape -> visitBuilding>(context, shape) @@ -425,10 +425,10 @@ internal object SimulationModel { root: Map<*, *>, ): List>, Molecule, () -> T>> { logger.debug("Visiting contents: {}", root) - val allContents = root[DocumentRoot.Deployment.contents] ?: emptyList() + val allContents = root[AlchemistYamlSyntax.Deployment.contents] ?: emptyList() return visitRecursively(context, allContents) { element -> logger.debug("Visiting as content: {}", element) - val moleculeKey = DocumentRoot.Deployment.Contents.molecule + val moleculeKey = AlchemistYamlSyntax.Deployment.Contents.molecule (element as? Map<*, *>)?.takeIf { element.containsKey(moleculeKey) }?.let { contentDescriptor -> logger.debug("Found content descriptor: {}", contentDescriptor) val filters = visitFilter

(context, element) @@ -440,7 +440,7 @@ internal object SimulationModel { } val molecule = incarnation.createMolecule(moleculeElement?.toString()) logger.debug("Molecule: {}", molecule) - val concentrationKey = DocumentRoot.Deployment.Contents.concentration + val concentrationKey = AlchemistYamlSyntax.Deployment.Contents.concentration val concentrationMaker: () -> T = { incarnation.createConcentration(element[concentrationKey]) } @@ -454,9 +454,9 @@ internal object SimulationModel { root: Map<*, *>, ): List>, NodeProperty>> { logger.debug("Visiting properties: {}", root) - val capabilitiesKey = DocumentRoot.Deployment.properties + val capabilitiesKey = AlchemistYamlSyntax.Deployment.properties val allCapabilities = root[capabilitiesKey] ?: emptyList() - return visitRecursively(context, allCapabilities, DocumentRoot.Deployment.Property) { element -> + return visitRecursively(context, allCapabilities, AlchemistYamlSyntax.Deployment.Property) { element -> (element as? Map<*, *>)?.let { val filters = visitFilter

(context, element) val nodeProperty = @@ -544,19 +544,19 @@ internal object SimulationModel { context: Context, root: Any?, ): Result>? = when { - root is String && root.equals(DocumentRoot.Export.Data.time, ignoreCase = true) -> Result.success(Time()) + root is String && root.equals(AlchemistYamlSyntax.Export.Data.time, ignoreCase = true) -> Result.success(Time()) - root is Map<*, *> && DocumentRoot.Export.Data.validateDescriptor(root) -> { - val molecule = root[DocumentRoot.Export.Data.molecule]?.toString() + root is Map<*, *> && AlchemistYamlSyntax.Export.Data.validateDescriptor(root) -> { + val molecule = root[AlchemistYamlSyntax.Export.Data.molecule]?.toString() if (molecule == null) { visitBuilding>(context, root) } else { - val property = root[DocumentRoot.Export.Data.property]?.toString() + val property = root[AlchemistYamlSyntax.Export.Data.property]?.toString() val filter: ExportFilter = - root[DocumentRoot.Export.Data.VALUE_FILTER]?.let { CommonFilters.fromString(it.toString()) } + root[AlchemistYamlSyntax.Export.Data.VALUE_FILTER]?.let { CommonFilters.fromString(it.toString()) } ?: CommonFilters.NOFILTER.filteringPolicy val precision: Int? = - when (val digits = root[DocumentRoot.Export.Data.precision]) { + when (val digits = root[AlchemistYamlSyntax.Export.Data.precision]) { null -> null is Byte -> digits.toInt() is Short -> digits.toInt() @@ -582,7 +582,7 @@ internal object SimulationModel { val aggregators: List = visitRecursively( context, - root[DocumentRoot.Export.Data.aggregators] ?: emptyList(), + root[AlchemistYamlSyntax.Export.Data.aggregators] ?: emptyList(), ) { require(it is CharSequence) { "Invalid aggregator $it:${it?.let { it::class.simpleName }}. Must be a String." @@ -601,11 +601,11 @@ internal object SimulationModel { context: Context, root: Any?, ): Result>? = when { - root is Map<*, *> && DocumentRoot.Export.validateDescriptor(root) -> { + root is Map<*, *> && AlchemistYamlSyntax.Export.validateDescriptor(root) -> { val exporter = visitBuilding>(context, root)?.getOrThrow() ?: cantBuildWith>(root) val dataExtractors = - visitRecursively(context, root[DocumentRoot.Export.data]) { + visitRecursively(context, root[AlchemistYamlSyntax.Export.data]) { visitExportData(incarnation, context, it) } exporter.bindDataExtractors(dataExtractors) @@ -637,7 +637,7 @@ internal object SimulationModel { } fun

, T> visitOutputMonitors(context: Context, root: Any?): List> = - visitRecursively(context, root ?: emptyList(), DocumentRoot.Monitor) { origin -> + visitRecursively(context, root ?: emptyList(), AlchemistYamlSyntax.Monitor) { origin -> (origin as? Map<*, *>)?.let { _ -> visitBuilding>(context, origin) } @@ -790,8 +790,8 @@ internal object SimulationModel { makeDefaultRandomGenerator(0).also { logger.warn( "No seeds specified, defaulting to 0 for both {} and {}", - DocumentRoot.Seeds.scenario, - DocumentRoot.Seeds.simulation, + AlchemistYamlSyntax.Seeds.scenario, + AlchemistYamlSyntax.Seeds.simulation, ) } is Map<*, *> -> { @@ -799,7 +799,7 @@ internal object SimulationModel { require(stringKeys.size == root.keys.size) { "Illegal seeds sub-keys: ${root.keys - stringKeys.toSet()}. Valid keys are: $stringKeys" } - val validKeys = DocumentRoot.Seeds.validKeys + val validKeys = AlchemistYamlSyntax.Seeds.validKeys val nonPrivateKeys = stringKeys.filterNot { it.startsWith("_") } require(nonPrivateKeys.all { it in validKeys }) { "Illegal seeds sub-keys: ${nonPrivateKeys - validKeys.toSet()}. Valid keys are: $validKeys" @@ -811,15 +811,15 @@ internal object SimulationModel { } else { 0 } - visitRandomGenerator(context, valueOf(DocumentRoot.Seeds.scenario)) to + visitRandomGenerator(context, valueOf(AlchemistYamlSyntax.Seeds.scenario)) to visitRandomGenerator( context, - valueOf(DocumentRoot.Seeds.simulation), + valueOf(AlchemistYamlSyntax.Seeds.simulation), ) } else -> throw IllegalArgumentException( - "Not a valid ${DocumentRoot.seeds} section: $root. Expected " + - DocumentRoot.Seeds.validKeys.map { it to "" }, + "Not a valid ${AlchemistYamlSyntax.seeds} section: $root. Expected " + + AlchemistYamlSyntax.Seeds.validKeys.map { it to "" }, ) } @@ -840,11 +840,11 @@ internal object SimulationModel { private fun visitVariables(context: Context, root: Any?): Map> = visitNamedRecursively( context, root, - syntax = DocumentRoot.Variable, + syntax = AlchemistYamlSyntax.Variable, ) { name, element -> (element as? Map<*, *>?) ?.takeIfNotAConstant(name, context) - ?.takeIf { DocumentRoot.Variable.validateDescriptor(element) } + ?.takeIf { AlchemistYamlSyntax.Variable.validateDescriptor(element) } ?.let { _ -> fun Any?.toDouble(): Double = coerceToDouble(context) val variable = @@ -858,10 +858,10 @@ internal object SimulationModel { runCatching { // Must be a linear variable, or else fail LinearVariable( - element[DocumentRoot.Variable.default].toDouble(), - element[DocumentRoot.Variable.min].toDouble(), - element[DocumentRoot.Variable.max].toDouble(), - element[DocumentRoot.Variable.step].toDouble(), + element[AlchemistYamlSyntax.Variable.default].toDouble(), + element[AlchemistYamlSyntax.Variable.min].toDouble(), + element[AlchemistYamlSyntax.Variable.max].toDouble(), + element[AlchemistYamlSyntax.Variable.step].toDouble(), ) } } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/Syntax.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/AlchemistYamlSyntax.kt similarity index 94% rename from alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/Syntax.kt rename to alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/AlchemistYamlSyntax.kt index da974eb0ac..7a36498f0d 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/Syntax.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/AlchemistYamlSyntax.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -9,9 +9,7 @@ package it.unibo.alchemist.boundary.loader.syntax -import kotlin.reflect.KProperty - -internal object DocumentRoot : SyntaxElement { +internal object AlchemistYamlSyntax : SyntaxElement { object JavaType : SyntaxElement { val type by OwnName val parameters by OwnName @@ -228,11 +226,7 @@ internal object DocumentRoot : SyntaxElement { optional(*validKeys.toTypedArray()) }, ) -} -internal object OwnName { - operator fun getValue(thisRef: Any?, property: KProperty<*>): String = property.name.lowercase() + private fun validDescriptor(configuration: DescriptorBuilder.() -> Unit): SyntaxElement.ValidDescriptor = + DescriptorBuilder().apply(configuration).build() } - -private fun validDescriptor(configuration: DescriptorBuilder.() -> Unit): SyntaxElement.ValidDescriptor = - DescriptorBuilder().apply(configuration).build() diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/OwnName.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/OwnName.kt new file mode 100644 index 0000000000..75704266d2 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/syntax/OwnName.kt @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.loader.syntax + +import kotlin.reflect.KProperty + +internal object OwnName { + operator fun getValue(thisRef: Any?, property: KProperty<*>): String = property.name.lowercase() +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/JVMConstructor.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/JVMConstructor.kt index 629a7c0d46..0c6a113f4b 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/JVMConstructor.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/JVMConstructor.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -14,190 +14,17 @@ import it.unibo.alchemist.util.ClassPathScanner import java.lang.reflect.Constructor import java.lang.reflect.Modifier import kotlin.reflect.KClass -import kotlin.reflect.KParameter import kotlin.reflect.full.valueParameters import kotlin.reflect.jvm.jvmErasure -import net.pearx.kasechange.splitToWords import org.danilopianini.jirf.CreationResult import org.danilopianini.jirf.Factory import org.danilopianini.jirf.InstancingImpossibleException import org.slf4j.LoggerFactory -/** - * A [JVMConstructor] whose [parameters] are an ordered list (common case for any JVM language). - */ -class OrderedParametersConstructor(type: String, val parameters: List<*> = emptyList()) : JVMConstructor(type) { - override fun parametersFor(target: KClass, factory: Factory): List<*> = parameters - - override fun toString(): String = "$typeName${parameters.joinToString(prefix = "(", postfix = ")")}" -} - -private typealias OrderedParameters = List - -/** - * A [JVMConstructor] whose parameters are named - * and hence stored in a [parametersMap] - * (no pure Java class works with named parameters now, Kotlin-only). - */ -class NamedParametersConstructor(type: String, val parametersMap: Map<*, *> = emptyMap()) : - JVMConstructor(type) { - private fun List.description() = joinToString(prefix = "\n- ", separator = "\n- ") { - it.namedParametersDescriptor() - } - - private inline infix fun Boolean.and(then: () -> Boolean): Boolean = if (this) then() else false - - private fun List.allLowerCase() = map { it.lowercase() } - - private fun String?.couldBeInterpretedAs(name: String?): Boolean = - equals(name, ignoreCase = true) || this?.splitToWords()?.allLowerCase() == name?.splitToWords()?.allLowerCase() - - override fun parametersFor(target: KClass, factory: Factory): List<*> { - val providedNames = parametersMap.map { it.key.toString() } - val singletons = factory.singletonObjects.keys - val constructorsWithOrderedParameters = - target.constructors.map { constructor -> - constructor.valueParameters.filterNot { it.type.jvmErasure.java in singletons }.sortedBy { it.index } - } - val usableConstructors: Map> = - constructorsWithOrderedParameters - .mapNotNull { parameters -> - if (providedNames.size <= parameters.size) { - // Parameter count must be compatible (as many or less parameters provided) - val (optional, mandatory) = parameters.partition { it.isOptional } - val mandatoryNames = mandatory.map { it.name } - val requiredOptionals by lazy { - optional - .take( - providedNames.size - mandatory.size, - ).map { it.name } - } - - fun verifyParameterMatch(matchMethod: (List).(List) -> Boolean) = - providedNames.matchMethod(mandatoryNames) and - { providedNames.matchMethod(requiredOptionals) } - // Check for exact name match - val exactMatch = verifyParameterMatch(List::containsAll) - if (exactMatch) { - parameters to emptyMap() - } else { - // Check for similar-enough non-ambiguous matches: kebab-case, snake_case, etc. - // convertedNames is a map between the actual parameter name and the provided name - val convertedNames = - providedNames - .mapNotNull { providedName -> - parameters - .filter { it.name.couldBeInterpretedAs(providedName) } - .takeIf { it.size == 1 } - ?.first() - ?.name - ?.let { it to providedName } - }.toMap() - val worksIfNamesAreReplaced = - convertedNames.keys.containsAll(mandatoryNames) and { - convertedNames.keys.containsAll(requiredOptionals) - } - if (worksIfNamesAreReplaced) { - parameters to convertedNames.filter { it.key != it.value } - } else { - null - } - } - } else { - null - } - }.toMap() - // If at least one constructor is a perfect match, discard the ones requiring name replacement. - val preferredMatch = - usableConstructors - .filterValues { replacements -> replacements.isEmpty() } - .takeIf { it.isNotEmpty() } - ?: usableConstructors - require(preferredMatch.isNotEmpty()) { - """ - No constructor available for ${target.simpleName} with named parameters $providedNames. - Note: Due to the way Kotlin's @JvmOverloads works, all the optional parameters that precede the ones - §of interest must be provided. - Available constructors have the following *named* parameters: - """.trimIndent().replace(Regex("\\R§"), " ") + - constructorsWithOrderedParameters.description() - } - require(preferredMatch.size == 1) { - """ - |Ambiguous constructors resolution for ${target.simpleName} with named parameters $providedNames. - |${ usableConstructors.keys.joinToString("\n|") { "Match: ${it.namedParametersDescriptor()}" } } - |Available constructors have the following *named* parameters: - """.trimMargin() + constructorsWithOrderedParameters.description() - } - val (selectedConstructor, replacements) = preferredMatch.toList().first() - if (replacements.isNotEmpty()) { - logger.warn( - "Alchemist had to replace some parameter names to match the constructor signature or {}: {}", - target.simpleName, - replacements, - ) - } - return selectedConstructor - .filter { parametersMap.containsKey(replacements.getOrDefault(it.name, it.name)) } - .map { parametersMap[replacements.getOrDefault(it.name, it.name)] } - } - - private fun Collection.namedParametersDescriptor() = "$size-ary constructor: " + - filter { it.name != null }.joinToString { - "${it.name}:${it.type.jvmErasure.simpleName}${if (it.isOptional) "" else "" }" - } - - override fun toString(): String = "$typeName($parametersMap)" - - private companion object { - @JvmStatic - private val logger = LoggerFactory.getLogger(NamedParametersConstructor::class.java) - } -} - -internal data class TypeSearch(val typeName: String, val targetType: Class) { - private val packageName: String? = typeName.substringBeforeLast('.', "").takeIf { it.isNotEmpty() } - private val isQualified get() = packageName != null - - val subTypes: Collection> by lazy { - val compatibleTypes: List> = - when (packageName) { - null -> - when { - targetType.packageName.startsWith("it.unibo.alchemist") -> - ClassPathScanner.subTypesOf(targetType, "it.unibo.alchemist") - else -> ClassPathScanner.subTypesOf(targetType) - } - else -> ClassPathScanner.subTypesOf(targetType, packageName) - } - when { - // The target type cannot be instanced, just return its concrete subclasses - Modifier.isAbstract(targetType.modifiers) -> compatibleTypes - // The target type can be instanced, return it and all its concrete subclasses - else -> mutableSetOf(targetType).apply { addAll(compatibleTypes) } - } - } - - val perfectMatches: List> by lazy { - subtypes(ignoreCase = false) - } - - val subOptimalMatches: List> by lazy { - subtypes(ignoreCase = true) - } - - private fun subtypes(ignoreCase: Boolean) = - subTypes.filter { typeName.equals(if (isQualified) it.name else it.simpleName, ignoreCase = ignoreCase) } - - companion object { - inline fun typeNamed(name: String) = TypeSearch(name, T::class.java) - } -} - /** * A constructor for a JVM class of type [typeName]. */ -sealed class JVMConstructor(val typeName: String) { +internal sealed class JVMConstructor(val typeName: String) { /** * provided a [target] class, extracts the parameters as an ordered list. */ diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/NamedParametersConstructor.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/NamedParametersConstructor.kt new file mode 100644 index 0000000000..5e2bfff4dd --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/NamedParametersConstructor.kt @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.loader.util + +import kotlin.collections.get +import kotlin.reflect.KClass +import kotlin.reflect.KParameter +import kotlin.reflect.full.valueParameters +import kotlin.reflect.jvm.jvmErasure +import net.pearx.kasechange.splitToWords +import org.danilopianini.jirf.Factory +import org.slf4j.LoggerFactory + +/** + * A [JVMConstructor] whose parameters are named + * and hence stored in a [parametersMap] + * (no pure Java class works with named parameters now, Kotlin-only). + */ +internal class NamedParametersConstructor(type: String, val parametersMap: Map<*, *> = emptyMap()) : + JVMConstructor(type) { + private fun List.description() = joinToString(prefix = "\n- ", separator = "\n- ") { + it.namedParametersDescriptor() + } + + private inline infix fun Boolean.and(then: () -> Boolean): Boolean = if (this) then() else false + + private fun List.allLowerCase() = map { it.lowercase() } + + private fun String?.couldBeInterpretedAs(name: String?): Boolean = + equals(name, ignoreCase = true) || this?.splitToWords()?.allLowerCase() == name?.splitToWords()?.allLowerCase() + + override fun parametersFor(target: KClass, factory: Factory): List<*> { + val providedNames = parametersMap.map { it.key.toString() } + val singletons = factory.singletonObjects.keys + val constructorsWithOrderedParameters = + target.constructors.map { constructor -> + constructor.valueParameters.filterNot { it.type.jvmErasure.java in singletons }.sortedBy { it.index } + } + val usableConstructors: Map> = + constructorsWithOrderedParameters + .mapNotNull { parameters -> + if (providedNames.size <= parameters.size) { + // Parameter count must be compatible (as many or less parameters provided) + val (optional, mandatory) = parameters.partition { it.isOptional } + val mandatoryNames = mandatory.map { it.name } + val requiredOptionals by lazy { + optional + .take( + providedNames.size - mandatory.size, + ).map { it.name } + } + + fun verifyParameterMatch(matchMethod: (List).(List) -> Boolean) = + providedNames.matchMethod(mandatoryNames) and + { providedNames.matchMethod(requiredOptionals) } + // Check for exact name match + val exactMatch = verifyParameterMatch(List::containsAll) + if (exactMatch) { + parameters to emptyMap() + } else { + // Check for similar-enough non-ambiguous matches: kebab-case, snake_case, etc. + // convertedNames is a map between the actual parameter name and the provided name + val convertedNames = + providedNames + .mapNotNull { providedName -> + parameters + .filter { it.name.couldBeInterpretedAs(providedName) } + .takeIf { it.size == 1 } + ?.first() + ?.name + ?.let { it to providedName } + }.toMap() + val worksIfNamesAreReplaced = + convertedNames.keys.containsAll(mandatoryNames) and { + convertedNames.keys.containsAll(requiredOptionals) + } + if (worksIfNamesAreReplaced) { + parameters to convertedNames.filter { it.key != it.value } + } else { + null + } + } + } else { + null + } + }.toMap() + // If at least one constructor is a perfect match, discard the ones requiring name replacement. + val preferredMatch = + usableConstructors + .filterValues { replacements -> replacements.isEmpty() } + .takeIf { it.isNotEmpty() } + ?: usableConstructors + require(preferredMatch.isNotEmpty()) { + """ + No constructor available for ${target.simpleName} with named parameters $providedNames. + Note: Due to the way Kotlin's @JvmOverloads works, all the optional parameters that precede the ones + §of interest must be provided. + Available constructors have the following *named* parameters: + """.trimIndent().replace(Regex("\\R§"), " ") + + constructorsWithOrderedParameters.description() + } + require(preferredMatch.size == 1) { + """ + |Ambiguous constructors resolution for ${target.simpleName} with named parameters $providedNames. + |${ usableConstructors.keys.joinToString("\n|") { "Match: ${it.namedParametersDescriptor()}" } } + |Available constructors have the following *named* parameters: + """.trimMargin() + constructorsWithOrderedParameters.description() + } + val (selectedConstructor, replacements) = preferredMatch.toList().first() + if (replacements.isNotEmpty()) { + logger.warn( + "Alchemist had to replace some parameter names to match the constructor signature or {}: {}", + target.simpleName, + replacements, + ) + } + return selectedConstructor + .filter { parametersMap.containsKey(replacements.getOrDefault(it.name, it.name)) } + .map { parametersMap[replacements.getOrDefault(it.name, it.name)] } + } + + private fun Collection.namedParametersDescriptor() = "$size-ary constructor: " + + filter { it.name != null }.joinToString { + "${it.name}:${it.type.jvmErasure.simpleName}${if (it.isOptional) "" else "" }" + } + + override fun toString(): String = "$typeName($parametersMap)" + + private companion object { + @JvmStatic + private val logger = LoggerFactory.getLogger(NamedParametersConstructor::class.java) + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/OrderedParameters.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/OrderedParameters.kt new file mode 100644 index 0000000000..cbd43aabc1 --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/OrderedParameters.kt @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.loader.util + +import kotlin.reflect.KParameter + +internal typealias OrderedParameters = List diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/OrderedParametersConstructor.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/OrderedParametersConstructor.kt new file mode 100644 index 0000000000..d20c6f954b --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/OrderedParametersConstructor.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.loader.util + +import kotlin.reflect.KClass +import org.danilopianini.jirf.Factory + +/** + * A [JVMConstructor] whose [parameters] are an ordered list (common case for any JVM language). + */ +internal class OrderedParametersConstructor(type: String, val parameters: List<*> = emptyList()) : + JVMConstructor(type) { + override fun parametersFor(target: KClass, factory: Factory): List<*> = parameters + + override fun toString(): String = "$typeName${parameters.joinToString(prefix = "(", postfix = ")")}" +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/TypeSearch.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/TypeSearch.kt new file mode 100644 index 0000000000..6ec701642e --- /dev/null +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/util/TypeSearch.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.boundary.loader.util + +import it.unibo.alchemist.util.ClassPathScanner +import java.lang.reflect.Modifier + +internal data class TypeSearch(val typeName: String, val targetType: Class) { + private val packageName: String? = typeName.substringBeforeLast('.', "").takeIf { it.isNotEmpty() } + private val isQualified get() = packageName != null + + val subTypes: Collection> by lazy { + val compatibleTypes: List> = + when (packageName) { + null -> + when { + targetType.packageName.startsWith("it.unibo.alchemist") -> + ClassPathScanner.subTypesOf(targetType, "it.unibo.alchemist") + else -> ClassPathScanner.subTypesOf(targetType) + } + else -> ClassPathScanner.subTypesOf(targetType, packageName) + } + when { + // The target type cannot be instanced, just return its concrete subclasses + Modifier.isAbstract(targetType.modifiers) -> compatibleTypes + // The target type can be instanced, return it and all its concrete subclasses + else -> mutableSetOf(targetType).apply { addAll(compatibleTypes) } + } + } + + val perfectMatches: List> by lazy { + subtypes(ignoreCase = false) + } + + val subOptimalMatches: List> by lazy { + subtypes(ignoreCase = true) + } + + private fun subtypes(ignoreCase: Boolean) = + subTypes.filter { typeName.equals(if (isQualified) it.name else it.simpleName, ignoreCase = ignoreCase) } + + companion object { + inline fun typeNamed(name: String) = TypeSearch(name, T::class.java) + } +} diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/JSR223Variable.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/JSR223Variable.kt index 55709122ed..11cfe7804a 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/JSR223Variable.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/variables/JSR223Variable.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -10,7 +10,7 @@ package it.unibo.alchemist.boundary.variables import it.unibo.alchemist.boundary.DependentVariable -import it.unibo.alchemist.boundary.loader.syntax.DocumentRoot +import it.unibo.alchemist.boundary.loader.syntax.AlchemistYamlSyntax import javax.script.Bindings import javax.script.ScriptEngineManager import javax.script.ScriptException @@ -83,7 +83,7 @@ constructor( because it reached its ${timeout}ms timeout. This is usually a sign that something is looping. Either make the script run faster, or allow for a longer time by specifiying a different - `${DocumentRoot.DependentVariable.timeout}`. + `${AlchemistYamlSyntax.DependentVariable.timeout}`. """.trimIndent().replace(Regex("\\R"), "") else -> """ diff --git a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts index f041194a6c..d2316338a6 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/11-monitors.alchemist.kts @@ -9,10 +9,8 @@ package dsl.kts import another.location.SimpleMonitor -import it.unibo.alchemist.boundary.dsl.Dsl.simulation +import it.unibo.alchemist.boundary.kotlindsl.simulation2D -simulation(SAPEREIncarnation()) { - monitors { - +SimpleMonitor() - } +simulation2D(SAPEREIncarnation()) { + monitor(SimpleMonitor()) } diff --git a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts index 18200544eb..1d07fd9df2 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts @@ -6,41 +6,19 @@ * GNU General Public License, with a linking exception, * as described in the file LICENSE in the Alchemist distribution's top directory. */ -import it.unibo.alchemist.model.sapere.ILsaMolecule -val incarnation: ProtelisIncarnation = ProtelisIncarnation() -simulation(incarnation) { - layer { - molecule = "A" - layer = StepLayer( - 2.0, - 2.0, - 100, - 0, - ) - } - layer { - molecule = "B" - layer = StepLayer( - -2.0, - -2.0, - 0, - 100, - ) - } - deployments { - deploy( - grid( - -5.0, - -5.0, - 5.0, - 5.0, - 0.25, - 0.1, - 0.1, - ), - ) { - all { - molecule = "a" +package dsl.kts +import it.unibo.alchemist.boundary.kotlindsl.environment +import it.unibo.alchemist.boundary.kotlindsl.simulation2D + +simulation2D(SAPEREIncarnation()) { + environment { + layer("A", StepLayer(2.0, 2.0, concentrationOf(100), concentrationOf(0))) + layer("B", StepLayer(-2.0, -2.0, concentrationOf(0), concentrationOf(100))) + deployments { + deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.1, 0.1)) { + contents { + - "a" + } } } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts index 8879b07896..2b9242c594 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts @@ -9,21 +9,16 @@ package dsl.kts -val incarnation = ProtelisIncarnation() -simulation(incarnation) { - exporter { - type = CSVExporter( - "test_export_interval", - 4.0, - ) - data( - Time(), - moleculeReader( - "default_module:default_program", - null, - CommonFilters.NOFILTER.filteringPolicy, - emptyList(), - ), +import it.unibo.alchemist.boundary.kotlindsl.simulation + +simulation(ProtelisIncarnation()) { + exportWith(CSVExporter("test_export_interval", 4.0)) { + - it.unibo.alchemist.boundary.extractors.Time() + - moleculeReader( + "default_module:default_program", + null, + CommonFilters.NOFILTER.filteringPolicy, + emptyList(), ) } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts index 067e00fefb..c83ff4fdfc 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts @@ -9,43 +9,30 @@ package dsl.kts -import it.unibo.alchemist.model.sapere.ILsaMolecule -import it.unibo.alchemist.model.times.DoubleTime -import it.unibo.alchemist.model.positionfilters.Rectangle as InRectangle +import it.unibo.alchemist.boundary.kotlindsl.TestDSLLoading.Companion.makePerturbedGridForTesting +import it.unibo.alchemist.boundary.kotlindsl.contains +import it.unibo.alchemist.boundary.kotlindsl.environment +import it.unibo.alchemist.boundary.kotlindsl.simulation2D +import it.unibo.alchemist.model.positionfilters.Rectangle -simulation(SAPEREIncarnation()) { +simulation2D(SAPEREIncarnation()) { val rate: Double by variable(GeometricVariable(2.0, 0.1, 10.0, 9)) val size: Double by variable(LinearVariable(5.0, 1.0, 10.0, 1.0)) - - val mSize by variable { -size } - val sourceStart by variable { mSize / 10.0 } - val sourceSize by variable { size / 5.0 } - terminators { +AfterTime, Euclidean2DPosition>(DoubleTime(1.0)) } - networkModel = ConnectWithinDistance(0.5) - deployments { - deploy( - grid( - mSize, - mSize, - size, - size, - 0.25, - 0.25, - 0.1, - 0.1, - ), - ) { - inside(InRectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { - molecule = "token, 0, []" - } - programs { - all { - timeDistribution(rate.toString()) - program = "{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}" - } - all { - program = "{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}" + environment { + val mSize = -size + val sourceStart = mSize / 10.0 + val sourceSize = size / 5.0 + terminator(AfterTime(DoubleTime(1.0))) + networkModel(ConnectWithinDistance(0.5)) + deployments { + deploy(makePerturbedGridForTesting()) { + if (position in Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { + contents { + -"token, 0, []" + } } + program("{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}", rate) + program("{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}") } } } From c2c85d045ede750cea2cacbd78066d05fe8fb4d6 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 15 Feb 2026 01:13:38 +0100 Subject: [PATCH 188/196] feat: update simulation scripts to use simulation2D and improve environment handling --- alchemist-kotlinscript/build.gradle.kts | 1 + .../modelproviders/KotlinDslProvider.kt | 4 +-- .../AlchemistCompilationConfiguration.kt | 16 ++++++++-- .../alchemist/kotlinscript/AlchemistScript.kt | 1 - .../kotlinscript/AlchemistScriptHost.kt | 2 +- .../alchemist/boundary/kotlindsl/DSLLoader.kt | 2 +- .../kotlindsl/KotlinDslProviderTest.kt | 6 ++-- .../dsl/kts/18-properties.alchemist.kts | 31 +++++++------------ .../dsl/kts/19-performance.alchemist.kts | 12 ++++--- .../src/test/resources/dsl/yml/12-layers.yml | 2 +- 10 files changed, 43 insertions(+), 34 deletions(-) rename {alchemist-loading => alchemist-kotlinscript}/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt (95%) diff --git a/alchemist-kotlinscript/build.gradle.kts b/alchemist-kotlinscript/build.gradle.kts index 8cb4df2515..9921a6a12f 100644 --- a/alchemist-kotlinscript/build.gradle.kts +++ b/alchemist-kotlinscript/build.gradle.kts @@ -19,6 +19,7 @@ dependencies { } implementation(alchemist("cognitive-agents")) implementation(alchemist("loading")) + implementation(alchemist("maps")) implementation(kotlin("script-runtime")) implementation(kotlin("scripting-common")) implementation(kotlin("scripting-jvm")) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt similarity index 95% rename from alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt rename to alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt index 5ac8d331ab..acfe3fe0ab 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt +++ b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -11,7 +11,7 @@ package it.unibo.alchemist.boundary.modelproviders import it.unibo.alchemist.boundary.AlchemistLoaderProvider import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.kotlindsl.AlchemistScript +import it.unibo.alchemist.kotlinscript.AlchemistScript import java.io.InputStream import java.io.Reader import java.net.URL diff --git a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistCompilationConfiguration.kt b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistCompilationConfiguration.kt index fd26729785..8c610037fa 100644 --- a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistCompilationConfiguration.kt +++ b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistCompilationConfiguration.kt @@ -11,11 +11,13 @@ package it.unibo.alchemist.kotlinscript import it.unibo.alchemist.boundary.kotlindsl.SimulationContext import it.unibo.alchemist.model.incarnations.ProtelisIncarnation +import it.unibo.alchemist.model.maps.environments.OSMEnvironment import kotlin.script.experimental.api.ScriptAcceptedLocation import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.api.acceptedLocations import kotlin.script.experimental.api.compilerOptions import kotlin.script.experimental.api.defaultImports +import kotlin.script.experimental.api.hostConfiguration import kotlin.script.experimental.api.ide import kotlin.script.experimental.jvm.dependenciesFromClassContext import kotlin.script.experimental.jvm.jvm @@ -24,7 +26,16 @@ import kotlin.script.experimental.jvm.jvm * Compilation configuration for Alchemist scripts. */ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ + val classes = listOf( + ProtelisIncarnation::class, + OSMEnvironment::class, + ) + val importsFromClasses = classes + .mapNotNull { it.qualifiedName?.substringBeforeLast('.') } + .distinct() + .map { "$it.*" } defaultImports( + *importsFromClasses.toTypedArray(), "it.unibo.alchemist.model.*", "it.unibo.alchemist.model.deployments.*", "it.unibo.alchemist.model.incarnations.*", @@ -51,12 +62,14 @@ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ "it.unibo.alchemist.boundary.properties.*", "it.unibo.alchemist.boundary.exporters.*", "it.unibo.alchemist.boundary.extractors.*", + "it.unibo.alchemist.boundary.kotlindsl.*", "it.unibo.alchemist.boundary.launchers.*", "it.unibo.alchemist.boundary.statistic.*", "it.unibo.alchemist.boundary.exportfilters.*", "it.unibo.alchemist.boundary.variables.*", - "it.unibo.alchemist.boundary.kotlindsl.*" ) + hostConfiguration + compilerOptions.append("-Xcontext-parameters") ide { acceptedLocations(ScriptAcceptedLocation.Everywhere) } @@ -64,7 +77,6 @@ object AlchemistCompilationConfiguration : ScriptCompilationConfiguration({ dependenciesFromClassContext(AlchemistScript::class, wholeClasspath = true) dependenciesFromClassContext(ProtelisIncarnation::class, wholeClasspath = true) dependenciesFromClassContext(SimulationContext::class, wholeClasspath = true) - compilerOptions.append("-Xcontext-parameters") } }) { // See: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/input.html diff --git a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt index 26356d2b13..e0108ce32b 100644 --- a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt +++ b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScript.kt @@ -20,4 +20,3 @@ import kotlin.script.experimental.annotations.KotlinScript compilationConfiguration = AlchemistCompilationConfiguration::class, ) interface AlchemistScript - diff --git a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt index 6be56a0ba1..331a7d6821 100644 --- a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt +++ b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt @@ -27,7 +27,7 @@ fun main(vararg args: String) { AlchemistCompilationConfiguration, ScriptEvaluationConfiguration { // jvm { mainArguments(scriptArgs) } - } + }, ) result.reports diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt index 0417987a77..a9808f2538 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt @@ -38,7 +38,7 @@ internal class DSLLoader, I : Incarnation>( private val logger = LoggerFactory.getLogger("Alchemist Kotlin DSL Loader") override var constants: Map = emptyMap() - override val remoteDependencies: List get() = TODO("Not yet implemented") + override val remoteDependencies: List get() = emptyList() override var launcher: Launcher = DefaultLauncher() override val dependentVariables: Map> = emptyMap() override var variables: Map> = emptyMap() diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt index 81be9495bb..b81a14e385 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt @@ -55,9 +55,9 @@ class KotlinDslProviderTest { @JvmStatic fun equivalenceCases(): Stream = Stream.of( Arguments.of("dsl/kts/12-layers.alchemist.kts", "dsl/yml/12-layers.yml"), - Arguments.of("dsl/kts/14-exporters.alchemist.kts", "dsl/yml/14-exporters.yml"), - Arguments.of("dsl/kts/15-variables.alchemist.kts", "dsl/yml/15-variables.yml"), - Arguments.of("dsl/kts/18-properties.alchemist.kts", "dsl/yml/18-properties.yml"), +// Arguments.of("dsl/kts/14-exporters.alchemist.kts", "dsl/yml/14-exporters.yml"), +// Arguments.of("dsl/kts/15-variables.alchemist.kts", "dsl/yml/15-variables.yml"), +// Arguments.of("dsl/kts/18-properties.alchemist.kts", "dsl/yml/18-properties.yml"), ) } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts index 5807df56a3..ea091bf075 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/18-properties.alchemist.kts @@ -9,27 +9,20 @@ package dsl.kts -import it.unibo.alchemist.model.positionfilters.Rectangle as InRectangle +import it.unibo.alchemist.boundary.kotlindsl.contains +import it.unibo.alchemist.boundary.kotlindsl.environment +import it.unibo.alchemist.boundary.kotlindsl.simulation2D +import it.unibo.alchemist.model.positionfilters.Rectangle -simulation(SAPEREIncarnation()) { - deployments { - deploy( - circle( - 1000, - 0.0, - 0.0, - 15.0, - ), - ) { - properties { - val filter = InRectangle(-3.0, -3.0, 2.0, 2.0) - val filter2 = InRectangle(3.0, 3.0, 2.0, 2.0) - inside(filter) { - +testNodeProperty("a") +simulation2D(SAPEREIncarnation()) { + environment { + deployments { + deploy(circle(1000, 0.0, 0.0, 15.0)) { + if (position in Rectangle(-3.0, -3.0, 2.0, 2.0)) { + nodeProperty(testNodeProperty("a")) } - // otherwise - inside(filter2) { - +testNodeProperty("b") + if (position in Rectangle(3.0, 3.0, 2.0, 2.0)) { + nodeProperty(testNodeProperty("b")) } } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts index c215f64456..2bcee3a77b 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts @@ -10,6 +10,10 @@ package dsl.kts import another.location.SimpleMonitor import it.unibo.alchemist.boundary.extractors.Time +import it.unibo.alchemist.boundary.kotlindsl.environment +import it.unibo.alchemist.boundary.kotlindsl.simulation2D +import it.unibo.alchemist.model.positionfilters.Rectangle +import kotlin.collections.emptyList simulation2D(SAPEREIncarnation()) { simulationSeed(24L) @@ -29,7 +33,7 @@ simulation2D(SAPEREIncarnation()) { deploy(circle(200, 0.0, 0.0, 20.0)) { contents { - "basemolecule" - if (position in Rectangle(-5.0, -5.0, 10.0, 10.0)) { + if (position in Rectangle(-5.0, -5.0, 10.0, 10.0)) { - "centermolecule" } program("1", 1.0) @@ -38,16 +42,16 @@ simulation2D(SAPEREIncarnation()) { deploy(grid(mSize, mSize, size, size, 0.25, 0.25, 0.1, 0.1)) { contents { - "gridmolecule" - if (position in Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { + if (position in Rectangle(sourceStart, sourceStart, sourceSize, sourceSize)) { -"token, 0, []" } - if (position in Rectangle(-2.0, -2.0, 4.0, 4.0)) { + if (position in Rectangle(-2.0, -2.0, 4.0, 4.0)) { -"filteredmolecule" } } program("{token, N, L} --> {token, N, L} *{token, N+#D, L add [#NODE;]}", rate) program("{token, N, L}{token, def: N2>=N, L2} --> {token, N, L}") - if (position in Rectangle(-1.0, -1.0, 2.0, 2.0)) { + if (position in Rectangle(-1.0, -1.0, 2.0, 2.0)) { program("{filteredmolecule} --> {active}", 0.5) } } diff --git a/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml b/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml index e18d04c92f..a54eb56c7c 100644 --- a/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml +++ b/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml @@ -1,4 +1,4 @@ -incarnation: protelis +incarnation: sapere environment: type: Continuous2DEnvironment From 18fe99eaaaf71ab2974d96026478ec67153f6c39 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 15 Feb 2026 01:16:27 +0100 Subject: [PATCH 189/196] feat: enable additional test cases for DSL script equivalence in KotlinDslProviderTest --- .../alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt index b81a14e385..81be9495bb 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt @@ -55,9 +55,9 @@ class KotlinDslProviderTest { @JvmStatic fun equivalenceCases(): Stream = Stream.of( Arguments.of("dsl/kts/12-layers.alchemist.kts", "dsl/yml/12-layers.yml"), -// Arguments.of("dsl/kts/14-exporters.alchemist.kts", "dsl/yml/14-exporters.yml"), -// Arguments.of("dsl/kts/15-variables.alchemist.kts", "dsl/yml/15-variables.yml"), -// Arguments.of("dsl/kts/18-properties.alchemist.kts", "dsl/yml/18-properties.yml"), + Arguments.of("dsl/kts/14-exporters.alchemist.kts", "dsl/yml/14-exporters.yml"), + Arguments.of("dsl/kts/15-variables.alchemist.kts", "dsl/yml/15-variables.yml"), + Arguments.of("dsl/kts/18-properties.alchemist.kts", "dsl/yml/18-properties.yml"), ) } } From ed349441ebf06bcfcea9d8b1652dc4907cba6f94 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 15 Feb 2026 02:03:38 +0100 Subject: [PATCH 190/196] feat: update incarnation from SAPERE to Protelis in simulation scripts --- .../alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt | 4 +--- .../src/test/resources/dsl/kts/12-layers.alchemist.kts | 2 +- alchemist-loading/src/test/resources/dsl/yml/12-layers.yml | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt index 08557931c9..09dd574fc7 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt @@ -98,8 +98,6 @@ object RuntimeComparisonHelper { stableForSteps, steps, ) - } catch (e: Exception) { - fail("Error during simulation execution: ${e.message}") } finally { // Ensure simulations are terminated (only if not already terminated) if (dslSimulation.status != Status.TERMINATED) { @@ -406,7 +404,7 @@ object RuntimeComparisonHelper { val (yamlNode, yamlPos) = closest val distance = dslPos.distanceTo(yamlPos) distances.add(distance) - if (distance != 0.0) { + if (distance == 0.0) { matchedPairs.add(dslNode to yamlNode) yamlNodesWithPos.remove(closest) } else { diff --git a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts index 1d07fd9df2..3046f69b07 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts @@ -10,7 +10,7 @@ package dsl.kts import it.unibo.alchemist.boundary.kotlindsl.environment import it.unibo.alchemist.boundary.kotlindsl.simulation2D -simulation2D(SAPEREIncarnation()) { +simulation2D(ProtelisIncarnation()) { environment { layer("A", StepLayer(2.0, 2.0, concentrationOf(100), concentrationOf(0))) layer("B", StepLayer(-2.0, -2.0, concentrationOf(0), concentrationOf(100))) diff --git a/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml b/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml index a54eb56c7c..e18d04c92f 100644 --- a/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml +++ b/alchemist-loading/src/test/resources/dsl/yml/12-layers.yml @@ -1,4 +1,4 @@ -incarnation: sapere +incarnation: protelis environment: type: Continuous2DEnvironment From 6761f380d3117c8789853e043a8cb7b62083d0e0 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 15 Feb 2026 15:01:46 +0100 Subject: [PATCH 191/196] feat: refactor DSL syntax and improve layer handling in environment --- .../it/unibo/alchemist/model/Environment.kt | 2 +- .../model/surrogates/EnvironmentSurrogate.kt | 4 +- .../model/environments/AbstractEnvironment.kt | 10 +- .../it/unibo/alchemist/boundary/Loader.kt | 2 +- .../boundary/exporters/CSVExporter.kt | 7 +- .../boundary/kotlindsl/ContentContext.kt | 76 ++- .../alchemist/boundary/kotlindsl/DSLLoader.kt | 4 +- .../unibo/alchemist/model/TestYAMLLoader.java | 6 +- .../kotlindsl/KotlinDslProviderTest.kt | 4 +- .../kotlindsl/LayerComparisonUtils.kt | 49 -- .../kotlindsl/PerformanceComparisonTest.kt | 4 +- .../kotlindsl/RuntimeComparisonHelper.kt | 589 ------------------ .../kotlindsl/SimulationsComparisons.kt | 122 ---- .../kotlindsl/StaticComparisonHelper.kt | 422 ------------- .../boundary/kotlindsl/TestComparators.kt | 182 +----- .../boundary/kotlindsl/TestContents.kt | 2 +- .../resources/dsl/kts/12-layers.alchemist.kts | 3 +- .../dsl/kts/14-exporters.alchemist.kts | 2 +- .../effect/impl/AbstractDrawLayers.java | 4 +- 19 files changed, 79 insertions(+), 1415 deletions(-) delete mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/LayerComparisonUtils.kt delete mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt delete mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationsComparisons.kt delete mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/StaticComparisonHelper.kt diff --git a/alchemist-api/src/main/kotlin/it/unibo/alchemist/model/Environment.kt b/alchemist-api/src/main/kotlin/it/unibo/alchemist/model/Environment.kt index beacb1bff9..5a781ab16d 100644 --- a/alchemist-api/src/main/kotlin/it/unibo/alchemist/model/Environment.kt +++ b/alchemist-api/src/main/kotlin/it/unibo/alchemist/model/Environment.kt @@ -83,7 +83,7 @@ interface Environment> : /** * Return all the Layers in this [Environment]. */ - val layers: ListSet> + val layers: Map> /** * Returns the current [LinkingRule]. diff --git a/alchemist-graphql-surrogates/src/main/kotlin/it/unibo/alchemist/boundary/graphql/schema/model/surrogates/EnvironmentSurrogate.kt b/alchemist-graphql-surrogates/src/main/kotlin/it/unibo/alchemist/boundary/graphql/schema/model/surrogates/EnvironmentSurrogate.kt index f23bb1310b..9df5c84dfd 100644 --- a/alchemist-graphql-surrogates/src/main/kotlin/it/unibo/alchemist/boundary/graphql/schema/model/surrogates/EnvironmentSurrogate.kt +++ b/alchemist-graphql-surrogates/src/main/kotlin/it/unibo/alchemist/boundary/graphql/schema/model/surrogates/EnvironmentSurrogate.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -55,7 +55,7 @@ data class EnvironmentSurrogate>( * @return the layers in this environment. */ @GraphQLDescription("The layers in this environment") - fun layers() = origin.layers.map { + fun layers() = origin.layers.values.map { it.toGraphQLLayerSurrogate { coordinates -> origin.makePosition(coordinates) } diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt index 2536b645b1..d87c77c006 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt @@ -54,12 +54,13 @@ abstract class AbstractEnvironment> protected constructor( ) : Environment { private val _nodes: ListSet> = ArrayListSet() private val _globalReactions = ArrayListSet>() - private val _layers: MutableMap> = LinkedHashMap() + final override var layers: Map> = LinkedHashMap() + private set private val neighCache = TIntObjectHashMap>() private val nodeToPos = TIntObjectHashMap

() private val spatialIndex: SpatialIndex> = internalIndex - override val layers: ListSet> get() = ArrayListSet(_layers.values) +// override val layers: Map> get() = _layers override val globalReactions: ListSet> get() = ListSets.unmodifiableListSet(_globalReactions) @@ -105,7 +106,8 @@ abstract class AbstractEnvironment> protected constructor( } override fun addLayer(molecule: Molecule, layer: Layer) { - check(_layers.put(molecule, layer) == null) { "Two layers have been associated to $molecule" } + check(molecule !in layers.keys) { "A layer for $molecule was already associated to this environment." } + layers += molecule to layer } override fun addGlobalReaction(reaction: GlobalReaction) { @@ -179,7 +181,7 @@ abstract class AbstractEnvironment> protected constructor( override fun getDistanceBetweenNodes(n1: Node, n2: Node): Double = getPosition(n1).distanceTo(getPosition(n2)) - override fun getLayer(molecule: Molecule): Layer? = _layers[molecule] + override fun getLayer(molecule: Molecule): Layer? = layers[molecule] override fun getNeighborhood(node: Node): Neighborhood { val result = neighCache[node.id] diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Loader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Loader.kt index bcedb5a930..5c4a53786f 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Loader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/Loader.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/exporters/CSVExporter.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/exporters/CSVExporter.kt index 047eef6405..f5594020ef 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/exporters/CSVExporter.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/exporters/CSVExporter.kt @@ -63,10 +63,9 @@ constructor( } val path = if (exportPath.endsWith(File.separator)) exportPath else "${exportPath}${File.separator}" val time = if (appendTime) "${System.currentTimeMillis()}" else "" - val filePrefix = - listOf(fileNameRoot, variablesDescriptor, time) - .filter(String::isNotBlank) - .joinToString(separator = "_") + val filePrefix = listOf(fileNameRoot, variablesDescriptor, time) + .filter(String::isNotBlank) + .joinToString(separator = "_") require(filePrefix.isNotEmpty()) { "No fileNameRoot provided for exporting data, no variables in the environment, and timestamp unset:" + "the file name would be empty. Please provide a file name." diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ContentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ContentContext.kt index 33156f5dbc..67c3c84a39 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ContentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ContentContext.kt @@ -23,62 +23,78 @@ import it.unibo.alchemist.model.Node * The API is based on Kotlin context receivers: the required [Incarnation] and/or [Node] are expected to be * available in the current context. */ -// TODO: Detekt false positive. Remove once Detekt supports context parameters. -@Suppress("UndocumentedPublicFunction") object ContentContext { /** - * Creates a concentration value using the current [Incarnation]. + * Assigns the given [concentration] to this [Molecule] on the current [Node]. * - * This is a convenience wrapper around [Incarnation.createConcentration] to keep DSL code concise. + * Context receivers: + * - [incarnation]: used to create concentrations by default when none is provided. + * - [node]: the target [Node] that will receive the concentration. * - * @param origin an optional value used by the [Incarnation] to derive the concentration. - * @return a concentration instance of type [T]. + * @receiver the molecule to which the concentration will be assigned + * @param concentration the concentration value to assign; when omitted, a fresh + * concentration instance is created via [Incarnation.createConcentration]. */ - context(incarnation: Incarnation) - fun concentrationOf(origin: Any?): T = incarnation.createConcentration(origin) + context(incarnation: Incarnation, node: Node) + operator fun Molecule.invoke(concentration: T = incarnation.createConcentration()) = + node.setConcentration(this, concentration) /** - * Assigns a concentration to the current [Node] for the given [Molecule]. + * Create the [Molecule] identified by this string using the current [Incarnation] + * and assign it the provided [concentration] on the current [Node]. * - * This operator enables concise DSL statements by interpreting `-(molecule to concentration)` as - * "set the concentration of this molecule on the current node". + * Context receivers: + * - [incarnation]: used to create the molecule and, by default, the concentration. + * - [node]: the target [Node] that will receive the concentration. * - * @receiver a pair `(molecule, concentration)` to assign. + * @receiver the molecule name (string) to create + * @param concentration the concentration value to assign; when omitted, a fresh + * concentration instance is created via [Incarnation.createConcentration]. */ - context(node: Node) - operator fun Pair.unaryMinus() { - node.setConcentration(first, second) - } + context(incarnation: Incarnation, node: Node) + operator fun String.invoke(concentration: T = incarnation.createConcentration()) = + incarnation.createMolecule(this)(concentration) /** - * Assigns a default concentration for this [Molecule] to the current [Node]. + * Creates a concentration value using the current [Incarnation]. * - * The concentration is created via [Incarnation.createConcentration] with no explicit origin. + * This is a convenience wrapper around [Incarnation.createConcentration] to keep DSL code concise. * - * @receiver the molecule whose concentration should be set. + * @param origin an optional value used by the [Incarnation] to derive the concentration. + * @return a concentration instance of type [T]. */ - context(incarnation: Incarnation, _: Node) - operator fun Molecule.unaryMinus() = -Pair(this, incarnation.createConcentration()) + context(incarnation: Incarnation) + fun concentrationOf(origin: Any?): T = incarnation.createConcentration(origin) /** - * Assigns a default concentration for the molecule identified by this string to the current [Node]. + * Assigns a default concentration for this [Molecule] to the current [Node]. * - * The [Molecule] is created via [Incarnation.createMolecule], while the concentration is created via - * [Incarnation.createConcentration] with no explicit origin. + * This operator invokes the parameterless molecule invoker, which in turn + * creates a default concentration via [Incarnation.createConcentration] and assigns + * it to the current [Node]. * - * @receiver the molecule name to create and set. + * Context receivers: + * - [incarnation]: used to create the default concentration + * - [Node]: the target node + * + * @receiver the molecule whose default concentration will be set on the current node */ context(incarnation: Incarnation, _: Node) - operator fun String.unaryMinus() = -Pair(incarnation.createMolecule(this), incarnation.createConcentration()) + operator fun Molecule.unaryMinus() = this() /** - * Assigns the provided concentration to the molecule identified by the given name on the current [Node]. + * Create a [Molecule] using its name and assign a default concentration to the current [Node]. + * + * This is equivalent to calling the string-based invoker with no explicit concentration + * and therefore creates and assigns a default concentration via the current [Incarnation]. * - * The molecule is created via [Incarnation.createMolecule]. + * Context receivers: + * - [incarnation]: used to create the molecule and its default concentration + * - [Node]: the target node * - * @receiver a pair `(moleculeName, concentration)` to assign. + * @receiver the molecule name to create and set with its default concentration */ context(incarnation: Incarnation, _: Node) - operator fun Pair.unaryMinus() = -Pair(incarnation.createMolecule(first), second) + operator fun String.unaryMinus() = this() } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt index a9808f2538..d26d269e56 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt @@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory internal class DSLLoader, I : Incarnation>( private val incarnation: I, - private val block: context(I) SimulationContext.() -> Unit, + private val simulationConfiguration: context(I) SimulationContext.() -> Unit, ) : Loader { private val logger = LoggerFactory.getLogger("Alchemist Kotlin DSL Loader") @@ -159,7 +159,7 @@ internal class DSLLoader, I : Incarnation>( "Seeds must be set before the environment is defined to preserve reproducibility" } } - }.block() + }.simulationConfiguration() } check(variables.keys.containsAll(values.keys)) { val undefinedVariables = values.keys - variables.keys diff --git a/alchemist-loading/src/test/java/it/unibo/alchemist/model/TestYAMLLoader.java b/alchemist-loading/src/test/java/it/unibo/alchemist/model/TestYAMLLoader.java index a3fed962e2..2239b2a69a 100644 --- a/alchemist-loading/src/test/java/it/unibo/alchemist/model/TestYAMLLoader.java +++ b/alchemist-loading/src/test/java/it/unibo/alchemist/model/TestYAMLLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2023, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -22,10 +22,10 @@ import org.kaikikm.threadresloader.ResourceLoader; import java.io.InputStream; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -91,7 +91,7 @@

> void testLayers() { final var simulation = testNoVar("synthetic/testlayer.yml"); @SuppressWarnings("unchecked") final Environment environment = (Environment) simulation.getEnvironment(); - final Set> layers = environment.getLayers(); + final Collection> layers = environment.getLayers().values(); assertFalse(layers.isEmpty()); assertEquals(2, layers.size()); assertEquals(2L, layers.stream() diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt index 81be9495bb..1a4d56a033 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt @@ -10,6 +10,7 @@ package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.boundary.LoadAlchemist +import it.unibo.alchemist.boundary.kotlindsl.TestComparators.shouldEqual import java.nio.file.Files import java.util.stream.Stream import kotlin.io.path.writeText @@ -47,8 +48,7 @@ class KotlinDslProviderTest { val url = requireNotNull(ResourceLoader.getResource(ktsResource)) { "Resource $ktsResource not found on test classpath" } - val loaderBuilder = { LoadAlchemist.from(url) } - loaderBuilder.shouldEqual(ymlResource) + LoadAlchemist.from(url).shouldEqual(ymlResource, steps = 10_000L) } companion object { diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/LayerComparisonUtils.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/LayerComparisonUtils.kt deleted file mode 100644 index 00019268db..0000000000 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/LayerComparisonUtils.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.kotlindsl - -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Position -import org.junit.jupiter.api.Assertions.assertEquals - -object LayerComparisonUtils { - fun > compareLayerValues(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing layer values...") - val samplePositions = mutableListOf

() - samplePositions.addAll(dslEnv.nodes.map { dslEnv.getPosition(it) }) - samplePositions.addAll(yamlEnv.nodes.map { yamlEnv.getPosition(it) }) - val uniquePositions = samplePositions.distinct() - if (uniquePositions.isNotEmpty()) { - for (position in uniquePositions) { - val dslLayerValues = dslEnv.layers.map { it.getValue(position) } - val yamlLayerValues = yamlEnv.layers.map { it.getValue(position) } - val dslDoubleValues = dslLayerValues.map { value -> - when (value) { - is Number -> value.toDouble() - else -> value.toString().toDoubleOrNull() ?: 0.0 - } - } - val yamlDoubleValues = yamlLayerValues.map { value -> - when (value) { - is Number -> value.toDouble() - else -> value.toString().toDoubleOrNull() ?: 0.0 - } - } - assertEquals( - yamlDoubleValues, - dslDoubleValues, - "Layer values at position $position should match", - ) - } - } else { - println("Skipping layer value comparison - no valid positions found") - } - } -} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt index f9d5dba2f0..7b1b713535 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt @@ -11,6 +11,7 @@ package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.boundary.LoadAlchemist import it.unibo.alchemist.boundary.Loader +import it.unibo.alchemist.boundary.kotlindsl.TestComparators.shouldEqual import it.unibo.alchemist.model.Position import java.io.ByteArrayOutputStream import java.io.File @@ -226,7 +227,6 @@ class PerformanceComparisonTest { val dslLoader = LoadAlchemist.from(dslFile) assertNotNull(yamlLoader) assertNotNull(dslLoader) - val dslLoaderFunction = { dslLoader } - dslLoaderFunction.shouldEqual(yamlResource, includeRuntime = false) + dslLoader.shouldEqual(yamlResource, 0L) } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt deleted file mode 100644 index 09dd574fc7..0000000000 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/RuntimeComparisonHelper.kt +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ -package it.unibo.alchemist.boundary.kotlindsl - -import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.core.Simulation -import it.unibo.alchemist.core.Status -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.Position -import it.unibo.alchemist.model.TerminationPredicate -import it.unibo.alchemist.model.Time -import it.unibo.alchemist.model.terminators.AfterTime -import it.unibo.alchemist.model.terminators.StableForSteps -import it.unibo.alchemist.model.terminators.StepCount -import it.unibo.alchemist.model.times.DoubleTime -import kotlin.math.abs -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.fail - -/** - * Helper for comparing DSL and YAML loaders by running simulations and comparing final states - * - * This class focuses on runtime behavior comparison by executing both simulations - * for a specified duration and comparing their final states. - * - */ -object RuntimeComparisonHelper { - - /** - * Compares loaders by running both simulations and comparing their final states. - * - * @param dslLoader The DSL loader to compare - * @param yamlLoader The YAML loader to compare - * @param steps The number of steps to run before comparing - * (if null, uses targetTime or stableForSteps instead) - * @param targetTime Target time to run until (if null, uses steps or stableForSteps instead). - * Only one termination method should be provided. - * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). - * Only one termination method should be provided. - * If null, calculated as max(timeTolerance * 10, 1e-6). - * For random movement tests, consider using a larger value (e.g., 1.0 or more). - * - * @note For simulations to advance time, all reactions must have explicit time distributions. - * Reactions without time distributions default to "Infinity" rate, which schedules - * them at time 0.0, preventing time from advancing. - * - * @note Step-based terminators ensure both simulations execute the same number of steps, - * but final times may differ slightly due to randomness. Time-based terminators - * ensure both simulations reach approximately the same time, but step counts may differ. - * StableForSteps terminators ensure both simulations terminate at a stable state, which - * works well for deterministic simulations (e.g., ReproduceGPSTrace) but may not work - * for random simulations (e.g., BrownianMove) if reactions execute in different orders. - * Small timing differences are expected even with time-based terminators due to thread - * scheduling and the terminator being checked after each step completes. - */ - fun > compareLoaders( - dslLoader: Loader, - yamlLoader: Loader, - steps: Long? = null, - targetTime: Double? = null, - stableForSteps: Pair? = null, - ) { - val terminationMethods = listOfNotNull( - steps?.let { "steps" }, - targetTime?.let { "targetTime" }, - stableForSteps?.let { "stableForSteps" }, - ) - require(terminationMethods.size == 1) { - "Exactly one termination method must be provided: steps, targetTime, or stableForSteps. " + - "Provided: $terminationMethods" - } - val effectiveSteps = steps ?: 0L - println("Running simulations for comparison...") - val dslSimulation = dslLoader.getDefault() - val yamlSimulation = yamlLoader.getDefault() - println( - "DSL simulation initial step: ${dslSimulation.step}, " + - "initial time: ${dslSimulation.time}", - ) - println( - "YAML simulation initial step: ${yamlSimulation.step}, " + - "initial time: ${yamlSimulation.time}", - ) - addTerminators(dslSimulation, yamlSimulation, steps, targetTime, stableForSteps) - try { - runAndCompareSimulations( - dslSimulation, - yamlSimulation, - effectiveSteps, - targetTime, - stableForSteps, - steps, - ) - } finally { - // Ensure simulations are terminated (only if not already terminated) - if (dslSimulation.status != Status.TERMINATED) { - dslSimulation.terminate() - } - if (yamlSimulation.status != Status.TERMINATED) { - yamlSimulation.terminate() - } - } - } - - private fun hasTerminationCondition( - effectiveSteps: Long, - targetTime: Double?, - stableForSteps: Pair?, - ): Boolean = effectiveSteps > 0 || targetTime != null || stableForSteps != null - - private fun > addTerminators( - dslSimulation: Simulation, - yamlSimulation: Simulation, - steps: Long?, - targetTime: Double?, - stableForSteps: Pair?, - ) { - when { - steps != null -> { - addStepTerminator(dslSimulation, steps) - addStepTerminator(yamlSimulation, steps) - println("Added step-based terminators for $steps steps") - } - targetTime != null -> { - val time = DoubleTime(targetTime) - addTimeTerminator(dslSimulation, time) - addTimeTerminator(yamlSimulation, time) - println("Added time-based terminators for ${targetTime}s") - } - stableForSteps != null -> { - val (checkInterval, equalIntervals) = stableForSteps - addStableTerminator(dslSimulation, checkInterval, equalIntervals) - addStableTerminator(yamlSimulation, checkInterval, equalIntervals) - println( - "Added stable-for-steps terminators " + - "(checkInterval: $checkInterval, equalIntervals: $equalIntervals)", - ) - } - } - } - - private fun > runAndCompareSimulations( - dslSimulation: Simulation, - yamlSimulation: Simulation, - effectiveSteps: Long, - targetTime: Double?, - stableForSteps: Pair?, - steps: Long?, - ) { - println("Running DSL simulation...") - runSimulationSynchronously(dslSimulation) - println( - "DSL simulation completed with status: ${dslSimulation.status}, " + - "step: ${dslSimulation.step}, time: ${dslSimulation.time}", - ) - println("Running YAML simulation...") - runSimulationSynchronously(yamlSimulation) - println( - "YAML simulation completed with status: ${yamlSimulation.status}, " + - "step: ${yamlSimulation.step}, time: ${yamlSimulation.time}", - ) - checkSimulationTimeAdvancement(dslSimulation, yamlSimulation, effectiveSteps, targetTime, stableForSteps) - compareRuntimeStates( - dslSimulation, - yamlSimulation, - compareSteps = steps != null, - ) - } - - private fun > checkSimulationTimeAdvancement( - dslSimulation: Simulation, - yamlSimulation: Simulation, - effectiveSteps: Long, - targetTime: Double?, - stableForSteps: Pair?, - ) { - val shouldHaveAdvanced = hasTerminationCondition(effectiveSteps, targetTime, stableForSteps) - if (dslSimulation.time.toDouble() == 0.0 && shouldHaveAdvanced) { - println( - "WARNING: DSL simulation time is 0.0. " + - "Ensure all reactions have explicit time distributions.", - ) - } - if (yamlSimulation.time.toDouble() == 0.0 && shouldHaveAdvanced) { - println( - "WARNING: YAML simulation time is 0.0. " + - "Ensure all reactions have explicit time distributions.", - ) - } - } - - /** - * Adds step-based terminator to a simulation. - */ - private fun > addStepTerminator(simulation: Simulation, steps: Long) { - simulation.environment.addTerminator(StepCount(steps)) - } - - /** - * Adds time-based terminator to a simulation. - */ - private fun > addTimeTerminator(simulation: Simulation, targetTime: Time) { - simulation.environment.addTerminator(AfterTime(targetTime)) - } - - /** - * Adds stable-for-steps terminator to a simulation. - * Terminates when environment (positions + node contents) remains unchanged - * for checkInterval * equalIntervals steps. - */ - private fun > addStableTerminator( - simulation: Simulation, - checkInterval: Long, - equalIntervals: Long, - ) { - val terminator = StableForSteps(checkInterval, equalIntervals) as - TerminationPredicate - simulation.environment.addTerminator(terminator) - } - - /** - * Runs a simulation synchronously (terminator will stop it). - */ - private fun > runSimulationSynchronously(simulation: Simulation) { - println(" Starting simulation thread, initial step: ${simulation.step}, initial time: ${simulation.time}") - val simulationThread = Thread(simulation, "Simulation-${System.currentTimeMillis()}") - simulationThread.start() - - while (simulation.status == Status.INIT) { - Thread.sleep(10) - } - println(" Simulation reached status: ${simulation.status}, step: ${simulation.step}, time: ${simulation.time}") - - while (simulation.status != Status.READY && simulation.status != Status.TERMINATED) { - Thread.sleep(10) - } - println( - " Simulation status after waiting: ${simulation.status}, " + - "step: ${simulation.step}, time: ${simulation.time}", - ) - - if (simulation.status == Status.TERMINATED) { - println(" Simulation already terminated before play()") - simulation.error.ifPresent { throw it } - return - } - - println(" Calling play(), step: ${simulation.step}, time: ${simulation.time}") - simulation.play().get() - println(" After play(), status: ${simulation.status}, step: ${simulation.step}, time: ${simulation.time}") - - simulationThread.join() - println(" Thread joined, final step: ${simulation.step}, final time: ${simulation.time}") - - simulation.error.ifPresent { throw it } - } - - /** - * Compares the final states of two simulations after runtime execution. - */ - private fun > compareRuntimeStates( - dslSimulation: Simulation, - yamlSimulation: Simulation, - compareSteps: Boolean = true, - ) { - println("Comparing runtime simulation states...") - - val dslEnv = dslSimulation.environment - val yamlEnv = yamlSimulation.environment - - // Compare simulation execution state - compareSimulationExecutionState(dslSimulation, yamlSimulation, compareSteps) - - // Compare environment states - compareRuntimeEnvironmentStates(dslEnv, yamlEnv) - } - - /** - * Compares simulation execution state (time, step, status, errors). - */ - private fun > compareSimulationExecutionState( - dslSimulation: Simulation, - yamlSimulation: Simulation, - compareSteps: Boolean = true, - ) { - println("Comparing simulation execution state...") - val dslTime = dslSimulation.time.toDouble() - val yamlTime = yamlSimulation.time.toDouble() - println("DSL simulation time: ${dslSimulation.time}, step: ${dslSimulation.step}") - println("YAML simulation time: ${yamlSimulation.time}, step: ${yamlSimulation.step}") - if (dslTime != yamlTime) { - fail( - "Simulation times differ by ${abs(dslTime - yamlTime)}s. DSL: ${dslTime}s, YAML: ${yamlTime}s", - ) - } - - // Compare step counts (only if using step-based terminator) - if (compareSteps) { - assertEquals( - yamlSimulation.step, - dslSimulation.step, - "Simulation step counts should match", - ) - } else { - val stepDiff = abs(yamlSimulation.step - dslSimulation.step) - println("Step difference: $stepDiff (not comparing - using time-based terminator)") - } - - // Compare status - assertEquals( - yamlSimulation.status, - dslSimulation.status, - "Simulation status should match", - ) - - // Compare error states - val dslError = dslSimulation.error - val yamlError = yamlSimulation.error - - if (dslError.isPresent != yamlError.isPresent) { - fail( - "Error states differ: DSL has error=${dslError.isPresent}, YAML has error=${yamlError.isPresent}", - ) - } - - if (dslError.isPresent && yamlError.isPresent) { - // Both have errors, compare error messages - val dslErrorMsg = dslError.get().message ?: "Unknown error" - val yamlErrorMsg = yamlError.get().message ?: "Unknown error" - if (dslErrorMsg != yamlErrorMsg) { - fail("Error messages differ: DSL='$dslErrorMsg', YAML='$yamlErrorMsg'") - } - } - } - - /** - * Compares environment states after runtime execution. - */ - private fun > compareRuntimeEnvironmentStates( - dslEnv: Environment, - yamlEnv: Environment, - ) { - println("Comparing runtime environment states...") - - // Compare basic environment properties - assertEquals( - yamlEnv.nodeCount, - dslEnv.nodeCount, - "Node counts should match after runtime", - ) - - assertEquals( - yamlEnv.dimensions, - dslEnv.dimensions, - "Environment dimensions should match", - ) - - // Compare node positions and contents - compareRuntimeNodeStates(dslEnv, yamlEnv) - - // Compare global reactions - compareRuntimeGlobalReactions(dslEnv, yamlEnv) - - // Compare layers - compareRuntimeLayers(dslEnv, yamlEnv) - } - - /** - * Compares node states after runtime execution using position-based matching with tolerance. - */ - private fun > compareRuntimeNodeStates(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing runtime node states...") - val dslNodesWithPos = dslEnv.nodes.map { it to dslEnv.getPosition(it) } - val yamlNodesWithPos = yamlEnv.nodes.map { it to yamlEnv.getPosition(it) }.toMutableList() - val (matchedPairs, unmatchedDslNodes, distances) = matchNodesByPosition( - dslNodesWithPos, - yamlNodesWithPos, - ) - printMatchingStatistics(distances, matchedPairs, dslNodesWithPos.size) - checkUnmatchedNodes(unmatchedDslNodes, yamlNodesWithPos, distances) - compareMatchedNodes(matchedPairs, dslEnv, yamlEnv) - } - - private fun > matchNodesByPosition( - dslNodesWithPos: List, P>>, - yamlNodesWithPos: MutableList, P>>, - ): Triple, Node>>, List, P>>, List> { - val matchedPairs = mutableListOf, Node>>() - val unmatchedDslNodes = mutableListOf, P>>() - val distances = mutableListOf() - - for ((dslNode, dslPos) in dslNodesWithPos) { - val closest = yamlNodesWithPos.minByOrNull { (_, yamlPos) -> - dslPos.distanceTo(yamlPos) - } - if (closest != null) { - val (yamlNode, yamlPos) = closest - val distance = dslPos.distanceTo(yamlPos) - distances.add(distance) - if (distance == 0.0) { - matchedPairs.add(dslNode to yamlNode) - yamlNodesWithPos.remove(closest) - } else { - unmatchedDslNodes.add(dslNode to dslPos) - } - } else { - unmatchedDslNodes.add(dslNode to dslPos) - } - } - - return Triple(matchedPairs, unmatchedDslNodes, distances) - } - - private fun printMatchingStatistics( - distances: List, - matchedPairs: List, Node>>, - totalNodes: Int, - ) { - if (distances.isNotEmpty()) { - val minDistance = distances.minOrNull() ?: Double.MAX_VALUE - val maxDistance = distances.maxOrNull() ?: 0.0 - val avgDistance = distances.average() - println( - "Position matching statistics: min=$minDistance, max=$maxDistance, " + - "avg=$avgDistance, matched=${matchedPairs.size}/$totalNodes", - ) - } - } - - private fun > checkUnmatchedNodes( - unmatchedDslNodes: List, P>>, - yamlNodesWithPos: List, P>>, - distances: List, - ) { - if (unmatchedDslNodes.isNotEmpty()) { - val minDistance = distances.minOrNull() ?: Double.MAX_VALUE - val maxDistance = distances.maxOrNull() ?: 0.0 - val avgDistance = distances.average() - val positions = unmatchedDslNodes.take(10).joinToString(", ") { (_, pos) -> pos.toString() } - val moreInfo = if (unmatchedDslNodes.size > 10) { - " ... and ${unmatchedDslNodes.size - 10} more" - } else { - "" - } - fail( - "DSL simulation has ${unmatchedDslNodes.size} unmatched nodes " + - "Distance stats: min=$minDistance, " + - "max=$maxDistance, avg=$avgDistance. First 10 positions: $positions$moreInfo", - ) - } - if (yamlNodesWithPos.isNotEmpty()) { - val positions = yamlNodesWithPos.take(10).joinToString(", ") { (_, pos) -> pos.toString() } - val moreInfo = if (yamlNodesWithPos.size > 10) { - " ... and ${yamlNodesWithPos.size - 10} more" - } else { - "" - } - fail( - "YAML simulation has ${yamlNodesWithPos.size} unmatched nodes " + - "at positions: $positions$moreInfo", - ) - } - } - - private fun > compareMatchedNodes( - matchedPairs: List, Node>>, - dslEnv: Environment, - yamlEnv: Environment, - ) { - for ((dslNode, yamlNode) in matchedPairs) { - val dslPos = dslEnv.getPosition(dslNode) - val yamlPos = yamlEnv.getPosition(yamlNode) - val distance = dslPos.distanceTo(yamlPos) - if (distance != 0.0) { - println("WARNING: Matched nodes have distance $distance ") - } - compareNodeContentsAtPosition(dslNode, yamlNode, dslPos) - } - } - - /** - * Compares contents of two nodes at the same position. - */ - private fun compareNodeContentsAtPosition(dslNode: Node, yamlNode: Node, position: Any) { - // Compare molecule counts - assertEquals( - yamlNode.moleculeCount, - dslNode.moleculeCount, - "Molecule counts should match at position $position", - ) - - // Compare all molecule concentrations - val dslContents = dslNode.contents - val yamlContents = yamlNode.contents - - // Get all unique molecule names - val allMolecules = (dslContents.keys + yamlContents.keys).distinct() - - for (molecule in allMolecules) { - val dslConcentration = dslContents[molecule] - val yamlConcentration = yamlContents[molecule] - - when { - dslConcentration == null && yamlConcentration == null -> { - // Both null, continue - } - dslConcentration == null -> { - fail("DSL node missing molecule $molecule at position $position") - } - yamlConcentration == null -> { - fail("YAML node missing molecule $molecule at position $position") - } - else -> { - // Both concentrations exist, compare them exactly - assertEquals( - yamlConcentration, - dslConcentration, - "Concentration of molecule $molecule should match at position $position", - ) - } - } - } - - // Compare reaction counts - assertEquals( - yamlNode.reactions.size, - dslNode.reactions.size, - "Reaction counts should match at position $position", - ) - } - - /** - * Compares global reactions after runtime execution. - */ - private fun > compareRuntimeGlobalReactions( - dslEnv: Environment, - yamlEnv: Environment, - ) { - println("Comparing runtime global reactions...") - - assertEquals( - yamlEnv.globalReactions.size, - dslEnv.globalReactions.size, - "Global reaction counts should match after runtime", - ) - - // Compare global reaction types - val dslGlobalTypes = dslEnv.globalReactions.map { it::class }.sortedBy { it.simpleName } - val yamlGlobalTypes = yamlEnv.globalReactions.map { it::class }.sortedBy { it.simpleName } - - assertEquals( - yamlGlobalTypes, - dslGlobalTypes, - "Global reaction types should match after runtime", - ) - } - - /** - * Compares layers after runtime execution. - */ - private fun > compareRuntimeLayers(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing runtime layers...") - - assertEquals( - yamlEnv.layers.size, - dslEnv.layers.size, - "Layer counts should match after runtime", - ) - - // Compare layer types - val dslLayerTypes = dslEnv.layers.map { it::class }.sortedBy { it.simpleName } - val yamlLayerTypes = yamlEnv.layers.map { it::class }.sortedBy { it.simpleName } - - assertEquals( - yamlLayerTypes, - dslLayerTypes, - "Layer types should match after runtime", - ) - - LayerComparisonUtils.compareLayerValues(dslEnv, yamlEnv) - } -} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationsComparisons.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationsComparisons.kt deleted file mode 100644 index 7eb79d77b8..0000000000 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationsComparisons.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ -package it.unibo.alchemist.boundary.kotlindsl - -import io.kotest.core.spec.style.AnnotationSpec -import it.unibo.alchemist.model.deployments.point -import it.unibo.alchemist.model.incarnations.SAPEREIncarnation -import it.unibo.alchemist.model.linkingrules.ConnectWithinDistance - -class SimulationsComparisons { - - @AnnotationSpec.Test - fun test01() { - simulation2D(SAPEREIncarnation()) { - environment { - networkModel(ConnectWithinDistance(5.0)) - deployments { - deploy(point(0, 0)) - deploy(point(1, 1)) - } - } - }.shouldEqual("dsl/yml/01-nodes.yml") - } - -// @Test -// fun test02() { -// { DslLoaderFunctions.test02ManyNodes() }.shouldEqual("dsl/yml/02-manynodes.yml") -// } -// -// @Test -// fun test03() { -// { DslLoaderFunctions.test03Grid() }.shouldEqual("dsl/yml/03-grid.yml") -// } -// -// @Test -// fun test05() { -// { DslLoaderFunctions.test05Content() }.shouldEqual("dsl/yml/05-content.yml") -// } -// -// @Test -// fun test06() { -// { DslLoaderFunctions.test06ContentFiltered() }.shouldEqual("dsl/yml/06-filters.yml") -// } -// -// @Test -// fun test07() { -// { DslLoaderFunctions.test07Programs() }.shouldEqual("dsl/yml/07-program.yml") -// } -// -// @Test -// fun test08() { -// DslLoaderFunctions.test08ProtelisPrograms().shouldEqual("dsl/yml/08-protelisprogram.yml") -// } -// -// @Test -// fun test09() { -// { DslLoaderFunctions.test09TimeDistribution() }.shouldEqual("dsl/yml/09-timedistribution.yml") -// } -// -// @Test -// fun test10() { -// { DslLoaderFunctions.test10Environment() }.shouldEqual("dsl/yml/10-environment.yml") -// } -// -// @Test -// fun test11() { -// { DslLoaderFunctions.test11monitors() }.shouldEqual("dsl/yml/11-monitors.yml") -// } -// -// @Test -// fun > test12() { -// { DslLoaderFunctions.test12Layers() }.shouldEqual("dsl/yml/12-layers.yml") -// } -// -// @Test -// fun > test13() { -// { DslLoaderFunctions.test13GlobalReaction() }.shouldEqual("dsl/yml/13-globalreaction.yml") -// } -// -// @Test -// fun > test14() { -// { DslLoaderFunctions.test14Exporters() }.shouldEqual("dsl/yml/14-exporters.yml") -// } -// -// @Test -// fun test15() { -// { DslLoaderFunctions.test15Variables() }.shouldEqual("dsl/yml/15-variables.yml") -// } -// -// @Test -// fun test16() { -// { DslLoaderFunctions.test16ProgramsFilters() } -// .shouldEqual( -// "dsl/yml/16-programsfilters.yml", -// targetTime = 10.0, -// ) -// } -// -// @Test -// fun test17() { -// { DslLoaderFunctions.test17CustomNodes() }.shouldEqual("dsl/yml/17-customnodes.yml") -// } -// -// @Test -// fun test18() { -// { DslLoaderFunctions.test18NodeProperties() }.shouldEqual("dsl/yml/18-properties.yml") -// } -// -// @Test -// fun test20() { -// { DslLoaderFunctions.test20Actions() }.shouldEqual( -// "dsl/yml/20-move.yml", -// targetTime = 10.0, -// ) -// } -} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/StaticComparisonHelper.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/StaticComparisonHelper.kt deleted file mode 100644 index 10daf1002f..0000000000 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/StaticComparisonHelper.kt +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ -package it.unibo.alchemist.boundary.kotlindsl - -import it.unibo.alchemist.boundary.Exporter -import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.exporters.GlobalExporter -import it.unibo.alchemist.core.Simulation -import it.unibo.alchemist.model.Environment -import it.unibo.alchemist.model.Node -import it.unibo.alchemist.model.Position -import org.junit.jupiter.api.Assertions.assertEquals - -/** - * Helper for comparing static properties of DSL and YAML loaders - * - * This class focuses on comparing the initial state and configuration - * of loaders without running the simulations. - */ -object StaticComparisonHelper { - - /** - * Compares basic loader properties. - */ - fun compareBasicProperties(dslLoader: Loader, yamlLoader: Loader) { - println("Comparing basic properties...") - - // Compare constants - assertEquals( - yamlLoader.constants, - dslLoader.constants, - "Constants should match", - ) - // Compare variables by name, default value, and full stream - val yamlVariables = yamlLoader.variables - val dslVariables = dslLoader.variables - assertEquals( - yamlVariables.keys, - dslVariables.keys, - "Variable names should match", - ) - yamlVariables.keys.forEach { name -> - val yamlVar = yamlVariables.getValue(name) - val dslVar = dslVariables.getValue(name) - assertEquals( - yamlVar.default, - dslVar.default, - "Default value of variable '$name' should match", - ) - val yamlValues = yamlVar.stream().toList() - val dslValues = dslVar.stream().toList() - assertEquals( - yamlValues, - dslValues, - "Values stream of variable '$name' should match", - ) - } - // Compare remote dependencies - assertEquals( - yamlLoader.remoteDependencies, - dslLoader.remoteDependencies, - "Remote dependencies should match", - ) - // Compare launcher types (not exact instances) - assertEquals( - yamlLoader.launcher::class, - dslLoader.launcher::class, - "Launcher types should match", - ) - } - - /** - * Compares the simulations generated by both loaders. - */ - fun > compareSimulations(dslLoader: Loader, yamlLoader: Loader) { - println("Comparing simulations...") - val yamlSimulation = yamlLoader.getDefault() - val dslSimulation = dslLoader.getDefault() - // Compare environments - compareEnvironments(dslSimulation.environment, yamlSimulation.environment) - // Compare simulation properties - compareSimulationProperties(dslSimulation, yamlSimulation) - } - - /** - * Compares two environments. - */ - private fun > compareEnvironments(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing environments...") - // Compare node counts - assertEquals( - yamlEnv.nodes.size, - dslEnv.nodes.size, - "Node counts should match", - ) - // compare nodes class names - val dslNodeTypes = dslEnv.nodes.map { it::class }.sortedBy { it.simpleName } - val yamlNodeTypes = yamlEnv.nodes.map { it::class }.sortedBy { it.simpleName } - assertEquals( - yamlNodeTypes, - dslNodeTypes, - "Node types should match", - ) - // Compare node positions - val dslPositions = dslEnv.nodes.map { dslEnv.getPosition(it) }.toSet() - val yamlPositions = yamlEnv.nodes.map { yamlEnv.getPosition(it) }.toSet() - assertEquals( - yamlPositions, - dslPositions, - "Node positions should match", - ) - // compare node properties - val dslNodeProperties = dslEnv.nodes.flatMap { it.properties }.map { it.toString() }.sortedBy { it } - val yamlNodeProperties = yamlEnv.nodes.flatMap { it.properties }.map { it.toString() }.sortedBy { it } - println(dslNodeProperties) - println(yamlNodeProperties) - assertEquals( - yamlNodeProperties, - dslNodeProperties, - "Node properties should match", - ) - // Compare node contents (molecules and concentrations) - compareNodeContents(dslEnv, yamlEnv) - - // Compare linking rules - assertEquals( - yamlEnv.linkingRule::class, - dslEnv.linkingRule::class, - "Linking rule types should match", - ) - // Compare neighborhoods induced by the linking rule - compareNeighborhoods(dslEnv, yamlEnv) - // Compare programs (reactions) - comparePrograms(dslEnv, yamlEnv) - // Compare layers - compareLayers(dslEnv, yamlEnv) - } - - /** - * Compares neighborhoods for each node matched by position in both environments. - */ - private fun > compareNeighborhoods(dslEnv: Environment, yamlEnv: Environment) { - val dslByPos = dslEnv.nodes.associateBy { dslEnv.getPosition(it) } - val yamlByPos = yamlEnv.nodes.associateBy { yamlEnv.getPosition(it) } - // Positions should already match; guard to provide clearer error if not - assertEquals( - yamlByPos.keys, - dslByPos.keys, - "Node position sets should match before neighborhood comparison", - ) - for (position in dslByPos.keys) { - val dslNode = dslByPos.getValue(position) - val yamlNode = yamlByPos.getValue(position) - val dslNeighborPositions = dslEnv - .getNeighborhood(dslNode) - .neighbors - .map { dslEnv.getPosition(it) } - .toSet() - val yamlNeighborPositions = yamlEnv - .getNeighborhood(yamlNode) - .neighbors - .map { yamlEnv.getPosition(it) } - .toSet() - assertEquals( - yamlNeighborPositions, - dslNeighborPositions, - "Neighborhood for node at $position should match", - ) - } - } - - /** - * Compares node contents (molecules and concentrations). - */ - private fun > compareNodeContents(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing node contents...") - // Since we can't match by position, we'll compare all nodes by their contents - val dslNodes = dslEnv.nodes.toList() - val yamlNodes = yamlEnv.nodes.toList() - // Compare total molecule counts - val dslTotalMolecules = dslNodes.sumOf { it.moleculeCount } - val yamlTotalMolecules = yamlNodes.sumOf { it.moleculeCount } - assertEquals( - yamlTotalMolecules, - dslTotalMolecules, - "Total molecule counts should match", - ) - // Compare all node contents (without position matching) - val dslContents = dslNodes.map { it.contents }.sortedBy { it.toString() } - val yamlContents = yamlNodes.map { it.contents }.sortedBy { it.toString() } - assertEquals( - yamlContents, - dslContents, - "All node contents (molecules and concentrations) should match", - ) - } - - /** - * Compares programs between environments. - */ - private fun > comparePrograms(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing programs...") - // Compare global reactions - compareGlobalReactions(dslEnv, yamlEnv) - // Compare node reactions - compareNodeReactions(dslEnv, yamlEnv) - } - - /** - * Compares global reactions. - */ - private fun > compareGlobalReactions(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing global reactions...") - val dslGlobalReactions = dslEnv.globalReactions.toList() - val yamlGlobalReactions = yamlEnv.globalReactions.toList() - assertEquals( - yamlGlobalReactions.size, - dslGlobalReactions.size, - "Global reactions count should match", - ) - // Compare global reaction types - val dslGlobalTypes = dslGlobalReactions.map { it::class }.sortedBy { it.simpleName } - val yamlGlobalTypes = yamlGlobalReactions.map { it::class }.sortedBy { it.simpleName } - assertEquals( - yamlGlobalTypes, - dslGlobalTypes, - "Global reaction types should match", - ) - } - - /** - * Compares node reactions (programs). - */ - private fun > compareNodeReactions(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing node reactions...") - val dslNodes = dslEnv.nodes.toList() - val yamlNodes = yamlEnv.nodes.toList() - // Compare total reaction counts - val dslTotalReactions = dslNodes.sumOf { it.reactions.size } - val yamlTotalReactions = yamlNodes.sumOf { it.reactions.size } - assertEquals( - yamlTotalReactions, - dslTotalReactions, - "Total node reactions count should match", - ) - // Compare reaction types across all nodes - val dslReactionTypes = dslNodes.flatMap { it.reactions }.map { it::class }.sortedBy { it.simpleName } - val yamlReactionTypes = yamlNodes.flatMap { it.reactions }.map { it::class }.sortedBy { it.simpleName } - assertEquals( - yamlReactionTypes, - dslReactionTypes, - "Node reaction types should match", - ) - // Compare reaction programs (conditions and actions) - compareReactionPrograms(dslNodes, yamlNodes) - } - - /** - * Compares reaction programs by comparing their string representations and dependencies. - */ - private fun compareReactionPrograms(dslNodes: List>, yamlNodes: List>) { - println("Comparing reaction programs...") - // Compare total reactions count - val dslTotalReactions = dslNodes.sumOf { it.reactions.size } - val yamlTotalReactions = yamlNodes.sumOf { it.reactions.size } - assertEquals( - yamlTotalReactions, - dslTotalReactions, - "Total reactions count should match", - ) - val dslReactions = extractReactionInfo(dslNodes) - val yamlReactions = extractReactionInfo(yamlNodes) - assertEquals( - yamlReactions, - dslReactions, - "Reaction string representations and dependencies should match", - ) - } - - /** - * Data class to represent reaction information for comparison. - */ - private data class ReactionInfo( - val reactionString: String, - val inboundDependencies: List, - val outboundDependencies: List, - ) { - override fun toString(): String = - "Reaction(string='$reactionString', inbound=$inboundDependencies, outbound=$outboundDependencies)" - } - - private fun extractReactionInfo(nodes: List>): List = nodes.flatMap { - it.reactions - }.map { reaction -> - ReactionInfo( - reactionString = try { - reaction.toString() - } catch (e: Exception) { - "" - }, - inboundDependencies = reaction.inboundDependencies.map { it.toString() }.sorted(), - outboundDependencies = reaction.outboundDependencies.map { it.toString() }.sorted(), - ) - }.sortedBy { it.toString() } - - /** - * Compares simulation properties. - */ - private fun compareSimulationProperties(dslSimulation: Simulation<*, *>, yamlSimulation: Simulation<*, *>) { - println("Comparing simulation properties...") - // Compare output monitors count - assertEquals( - yamlSimulation.outputMonitors.size, - dslSimulation.outputMonitors.size, - "Output monitors count should match", - ) - - // Compare output monitor types by class since instances may differ - val yamlMonitorTypes = yamlSimulation.outputMonitors.map { it::class } - val dslMonitorTypes = dslSimulation.outputMonitors.map { it::class } - assertEquals( - yamlMonitorTypes.sortedBy { it.simpleName }, - dslMonitorTypes.sortedBy { it.simpleName }, - "Output monitor types should match", - ) - compareExporters(dslSimulation, yamlSimulation) - } - - private fun compareExporters(dslSimulation: Simulation<*, *>, yamlSimulation: Simulation<*, *>) { - val dslExporters = dslSimulation.outputMonitors - .filterIsInstance>() - .flatMap { it.exporters } - val yamlExporters = yamlSimulation.outputMonitors - .filterIsInstance>() - .flatMap { it.exporters } - assertEquals( - yamlExporters.size, - dslExporters.size, - "Exporter counts should match", - ) - - val dslTypes = dslExporters.map { it::class }.sortedBy { it.simpleName } - val yamlTypes = yamlExporters.map { it::class }.sortedBy { it.simpleName } - assertEquals( - yamlTypes, - dslTypes, - "Exporter types should match", - ) - compareDataExtractors(dslExporters, yamlExporters) - } - - private fun compareDataExtractors(dslExporters: List>, yamlExporters: List>) { - val dslTotal = dslExporters.sumOf { it.dataExtractors.size } - val yamlTotal = yamlExporters.sumOf { it.dataExtractors.size } - assertEquals( - yamlTotal, - dslTotal, - "Total data extractor counts should match", - ) - val dslTypes = dslExporters.flatMap { it.dataExtractors }.map { it::class }.sortedBy { it.simpleName } - val yamlTypes = yamlExporters.flatMap { it.dataExtractors }.map { it::class }.sortedBy { it.simpleName } - assertEquals( - yamlTypes, - dslTypes, - "Data extractor types should match", - ) - val dslInfo = dslExporters.flatMap { it.dataExtractors }.map { extractor -> - ExtractorInfo( - type = extractor::class.simpleName.orEmpty(), - columns = extractor.columnNames.sorted(), - ) - }.sortedBy { it.toString() } - val yamlInfo = yamlExporters.flatMap { it.dataExtractors }.map { extractor -> - ExtractorInfo( - type = extractor::class.simpleName.orEmpty(), - columns = extractor.columnNames.sorted(), - ) - }.sortedBy { it.toString() } - assertEquals( - yamlInfo, - dslInfo, - "Data extractor information (types and column names) should match", - ) - } - - private data class ExtractorInfo( - val type: String, - val columns: List, - ) { - override fun toString(): String = "Extractor(type=$type, columns=$columns)" - } - - /** - * Compares layers between environments. - */ - private fun > compareLayers(dslEnv: Environment, yamlEnv: Environment) { - println("Comparing layers...") - // Simplified check - // If two layers have different molecules this test does not detect it. - // Compare layer counts - assertEquals( - yamlEnv.layers.size, - dslEnv.layers.size, - "Layer counts should match", - ) - // Compare layer types - val dslLayerTypes = dslEnv.layers.map { it::class }.sortedBy { it.simpleName } - val yamlLayerTypes = yamlEnv.layers.map { it::class }.sortedBy { it.simpleName } - assertEquals( - yamlLayerTypes, - dslLayerTypes, - "Layer types should match", - ) - LayerComparisonUtils.compareLayerValues(dslEnv, yamlEnv) - } -} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestComparators.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestComparators.kt index c29371d5a2..870df9d85d 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestComparators.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestComparators.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2025, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -10,6 +10,7 @@ package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.boundary.Loader import it.unibo.alchemist.model.Position +import it.unibo.alchemist.test.equalsForSteps /** * Main test comparison class that handles static and runtime comparisons @@ -22,187 +23,14 @@ object TestComparators { /** * Compares a DSL loader with a YAML loader. * - * @param dslLoader The DSL loader to compare. + * @param other The DSL loader to compare. * @param yamlResource The YAML resource path to compare against. - * @param includeRuntime Whether to include runtime behavior comparison. * @param steps The number of steps for runtime comparison (only used if includeRuntime is true). * Exactly one of steps, targetTime, or stableForSteps must be provided. - * @param targetTime Target time to run until (only used if includeRuntime is true). - * Exactly one of steps, targetTime, or stableForSteps must be provided. - * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). - * Exactly one of steps, targetTime, or stableForSteps must be provided. */ - fun > compare( - dslLoader: () -> Loader, - yamlResource: String, - includeRuntime: Boolean = false, - steps: Long? = null, - targetTime: Double? = null, - stableForSteps: Pair? = null, - ) { + fun > Loader.shouldEqual(yamlResource: String, steps: Long = 0L) { val yamlLoader = LoaderFactory.loadYaml(yamlResource) // Always perform static comparison - StaticComparisonHelper.compareBasicProperties(dslLoader(), yamlLoader) - StaticComparisonHelper.compareSimulations(dslLoader(), yamlLoader) - // Optionally perform runtime comparison - if (includeRuntime) { - RuntimeComparisonHelper.compareLoaders( - dslLoader(), - yamlLoader, - steps = steps, - targetTime = targetTime, - stableForSteps = stableForSteps, - ) - } - } - - /** - * Compares DSL code with a YAML resource. - * - * @param dslCode The DSL code resource path. - * @param yamlResource The YAML resource path to compare against. - * @param includeRuntime Whether to include runtime behavior comparison. - * @param steps The number of steps for runtime comparison (only used if includeRuntime is true). - * Exactly one of steps, targetTime, or stableForSteps must be provided. - * @param targetTime Target time to run until (only used if includeRuntime is true). - * Exactly one of steps, targetTime, or stableForSteps must be provided. - * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). - * Exactly one of steps, targetTime, or stableForSteps must be provided. - */ - fun > compare( - dslCode: String, - yamlResource: String, - includeRuntime: Boolean = false, - steps: Long? = null, - targetTime: Double? = null, - stableForSteps: Pair? = null, - ) { - compare({ - LoaderFactory.loadDsl(dslCode) - }, yamlResource, includeRuntime, steps, targetTime, stableForSteps) - } - - /** - * Compares two loaders directly. - * - * @param dslLoader The DSL loader to compare. - * @param yamlLoader The YAML loader to compare against. - * @param includeRuntime Whether to include runtime behavior comparison. - * @param steps The number of steps for runtime comparison (only used if includeRuntime is true). - * Exactly one of steps, targetTime, or stableForSteps must be provided. - * @param targetTime Target time to run until (only used if includeRuntime is true). - * Exactly one of steps, targetTime, or stableForSteps must be provided. - * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). - * Exactly one of steps, targetTime, or stableForSteps must be provided. - */ - fun > compare( - dslLoader: Loader, - yamlLoader: Loader, - includeRuntime: Boolean = false, - steps: Long? = null, - targetTime: Double? = null, - stableForSteps: Pair? = null, - ) { - // Always perform static comparison - StaticComparisonHelper.compareBasicProperties(dslLoader, yamlLoader) - StaticComparisonHelper.compareSimulations(dslLoader, yamlLoader) - // Optionally perform runtime comparison - if (includeRuntime) { - RuntimeComparisonHelper.compareLoaders( - dslLoader, - yamlLoader, - steps = steps, - targetTime = targetTime, - stableForSteps = stableForSteps, - ) - } + getDefault().equalsForSteps(yamlLoader.getDefault(), steps) } } - -private const val DEFAULT_STEPS = 3000L - -private fun computeEffectiveSteps( - includeRuntime: Boolean, - steps: Long?, - targetTime: Double?, - stableForSteps: Pair?, -): Long? { - val shouldUseDefault = includeRuntime && steps == null && targetTime == null && stableForSteps == null - return if (shouldUseDefault) DEFAULT_STEPS else steps -} - -/** - * Extension function for easier test writing with static comparison only. - */ -fun Loader.shouldEqual(yamlResource: String) { - @Suppress("UNCHECKED_CAST") - TestComparators.compare({ this }, yamlResource, includeRuntime = false) -} - -/** - * Extension function for comparing two loaders. - * - * @param other The other loader to compare against - * @param includeRuntime Whether to include runtime behavior comparison - * @param steps The number of steps for runtime comparison. - * If includeRuntime is true and no termination method is provided, defaults to 3000L. - * @param targetTime Target time to run until. - * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. - * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). - * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. - */ -fun Loader.shouldEqual( - other: Loader, - includeRuntime: Boolean = true, - steps: Long? = null, - targetTime: Double? = null, - stableForSteps: Pair? = null, -) { - TestComparators.compare( - this, - other, - includeRuntime, - computeEffectiveSteps(includeRuntime, steps, targetTime, stableForSteps), - targetTime, - stableForSteps, - ) -} - -/** - * Extension function for comparing DSL function with YAML resource. - * - * @param yamlResource The YAML resource path to compare against - * @param includeRuntime Whether to include runtime behavior comparison - * @param steps The number of steps for runtime comparison. - * If includeRuntime is true and no termination method is provided, defaults to 3000L. - * @param targetTime Target time to run until. - * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. - * @param stableForSteps If provided, terminates when environment is stable (checkInterval, equalIntervals). - * Exactly one of steps, targetTime, or stableForSteps must be provided when includeRuntime is true. - * @note For simulations to advance time, all reactions must have explicit time distributions. - * Reactions without time distributions default to "Infinity" rate, which schedules - * them at time 0.0, preventing time from advancing. - * - * @note Step-based terminators ensure both simulations execute the same number of steps, - * but final times may differ slightly due to randomness. Time-based terminators - * ensure both simulations reach approximately the same time, but step counts may differ. - * StableForSteps terminators ensure both simulations terminate at a stable state, which - * works well for deterministic simulations (e.g., ReproduceGPSTrace) but may not work - * for random simulations (e.g., BrownianMove) if reactions execute in different orders. - */ -fun (() -> Loader).shouldEqual( - yamlResource: String, - includeRuntime: Boolean = true, - steps: Long? = null, - targetTime: Double? = null, - stableForSteps: Pair? = null, -) { - TestComparators.compare( - this, - yamlResource, - includeRuntime, - computeEffectiveSteps(includeRuntime, steps, targetTime, stableForSteps), - targetTime, - stableForSteps, - ) -} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestContents.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestContents.kt index f6c4e88ee1..7d504d7ab1 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestContents.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestContents.kt @@ -23,7 +23,7 @@ class TestContents { deployments { deploy(point(0.0, 0.0)) { contents { - -"test" to listOf(LsaMolecule("1")) + "test"(listOf(LsaMolecule("1"))) } } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts index 3046f69b07..94ec000c0e 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts @@ -7,6 +7,7 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ package dsl.kts +import it.unibo.alchemist.boundary.kotlindsl.ContentContext.unaryMinus import it.unibo.alchemist.boundary.kotlindsl.environment import it.unibo.alchemist.boundary.kotlindsl.simulation2D @@ -17,7 +18,7 @@ simulation2D(ProtelisIncarnation()) { deployments { deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.1, 0.1)) { contents { - - "a" + -just("a") } } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts index 2b9242c594..0480b11a2d 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/14-exporters.alchemist.kts @@ -12,7 +12,7 @@ package dsl.kts import it.unibo.alchemist.boundary.kotlindsl.simulation simulation(ProtelisIncarnation()) { - exportWith(CSVExporter("test_export_interval", 4.0)) { + exportWith(CSVExporter("test_export_interval", 3.0)) { - it.unibo.alchemist.boundary.extractors.Time() - moleculeReader( "default_module:default_program", diff --git a/alchemist-swingui/src/main/java/it/unibo/alchemist/boundary/swingui/effect/impl/AbstractDrawLayers.java b/alchemist-swingui/src/main/java/it/unibo/alchemist/boundary/swingui/effect/impl/AbstractDrawLayers.java index fe92c127d4..e02301943b 100644 --- a/alchemist-swingui/src/main/java/it/unibo/alchemist/boundary/swingui/effect/impl/AbstractDrawLayers.java +++ b/alchemist-swingui/src/main/java/it/unibo/alchemist/boundary/swingui/effect/impl/AbstractDrawLayers.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022, Danilo Pianini and contributors + * Copyright (C) 2010-2026, Danilo Pianini and contributors * listed, for each module, in the respective subproject's build.gradle.kts file. * * This file is part of Alchemist, and is distributed under the terms of the @@ -100,7 +100,7 @@ protected > void draw( if (layerFilter && molecule != null && environment.getLayer(molecule) != null) { toDraw.add(environment.getLayer(molecule)); } else { - toDraw.addAll(environment.getLayers()); + toDraw.addAll(environment.getLayers().values()); } if (!toDraw.isEmpty()) { drawLayers(toDraw, environment, graphics2D, wormhole); From 87af1d29ec44892525347b9cf23c26f78943dc64 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 15 Feb 2026 19:15:06 +0100 Subject: [PATCH 192/196] feat: simplify DSL syntax and enhance variable handling in simulation scripts --- .../modelproviders/KotlinDslProvider.kt | 22 +- .../boundary/exporters/CSVExporter.kt | 49 ++-- .../alchemist/boundary/kotlindsl/DSLLoader.kt | 10 +- .../boundary/loader/LoadingSystem.kt | 22 +- .../boundary/loader/SimulationModel.kt | 1 - .../kotlindsl/KotlinDslProviderTest.kt | 1 + .../kotlindsl/PerformanceComparisonTest.kt | 232 ------------------ .../boundary/kotlindsl/TestVariables.kt | 6 +- .../resources/dsl/kts/12-layers.alchemist.kts | 3 +- .../dsl/kts/15-variables.alchemist.kts | 1 - .../dsl/kts/19-performance.alchemist.kts | 7 +- .../test/resources/dsl/yml/19-performance.yml | 11 - .../it/unibo/alchemist/test/Assertions.kt | 152 ++++++++++++ 13 files changed, 220 insertions(+), 297 deletions(-) delete mode 100644 alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt create mode 100644 alchemist-test/src/main/kotlin/it/unibo/alchemist/test/Assertions.kt diff --git a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt index acfe3fe0ab..5eb34f88ab 100644 --- a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt +++ b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/boundary/modelproviders/KotlinDslProvider.kt @@ -18,7 +18,7 @@ import java.net.URL import kotlin.script.experimental.api.ResultValue import kotlin.script.experimental.api.ScriptDiagnostic import kotlin.script.experimental.api.ScriptEvaluationConfiguration -import kotlin.script.experimental.api.valueOrNull +import kotlin.script.experimental.api.valueOrThrow import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.jvm.baseClassLoader import kotlin.script.experimental.jvm.jvm @@ -47,9 +47,23 @@ object KotlinDslProvider : AlchemistLoaderProvider { val result = host.eval(input.toScriptSource(), compilationConfiguration, evaluationConfiguration) val errors = result.reports.filter { it.severity == ScriptDiagnostic.Severity.ERROR } require(errors.isEmpty()) { errors.joinToString("\n") { it.message } } - val value = (result.valueOrNull()?.returnValue as? ResultValue.Value)?.value - return value as? Loader - ?: error("Script must return a Loader; got ${value?.let { it::class.qualifiedName } ?: "null"}") + return when (val resultValue = result.valueOrThrow().returnValue) { + is ResultValue.Value -> { + val value = resultValue.value + check(value is Loader) { + "Script must return a Loader; got ${value?.let { "$it: ${it::class.qualifiedName}" }}" + } + value + } + is ResultValue.Error -> { + throw resultValue.error + } + is ResultValue.Unit -> + error("Script returned Unit; expected a Loader (use 'simulation { ... }' as the last statement)") + is ResultValue.NotEvaluated -> { + error("Script was not evaluated") + } + } } override fun from(input: Reader): Loader = from(input.readText()) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/exporters/CSVExporter.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/exporters/CSVExporter.kt index f5594020ef..6599ebbbd4 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/exporters/CSVExporter.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/exporters/CSVExporter.kt @@ -96,37 +96,36 @@ constructor( } override fun exportData(environment: Environment, reaction: Actionable?, time: Time, step: Long) { - val line: String = - dataExtractors.joinToString(separator = " ") { extractor -> - val data = extractor.extractDataAsText(environment, reaction, time, step) - val names = extractor.columnNames - when { - data.size <= 1 -> data.values.joinToString(" ") - // Labels and keys match - data.size == names.size && data.keys.containsAll(names) -> - names.joinToString(" ") { - requireNotNull(data[it]) { - BugReporting.reportBug( - "Bug in ${this::class.simpleName}", - mapOf("key" to it, "data" to data), - ) - } - } - // If the labels do not match keys, require predictable iteration order - else -> { - require(data.hasPredictableIteration) { + val line: String = dataExtractors.joinToString(separator = " ") { extractor -> + val data = extractor.extractDataAsText(environment, reaction, time, step) + val names = extractor.columnNames + when { + data.size <= 1 -> data.values.joinToString(" ") + // Labels and keys match + data.size == names.size && data.keys.containsAll(names) -> + names.joinToString(" ") { + requireNotNull(data[it]) { BugReporting.reportBug( - """ - Extractor "${extractor::class.simpleName}" is likely bugged: - 1. the set of labels $names does not match the keys ${data.keys}, but iteration may fail as - 2. it returned a map with non-predictable iteration order of type ${data::class.simpleName}" - """.trimIndent(), + "Bug in ${this::class.simpleName}", + mapOf("key" to it, "data" to data), ) } - data.values.joinToString(" ") } + // If the labels do not match keys, require predictable iteration order + else -> { + require(data.hasPredictableIteration) { + BugReporting.reportBug( + """ + Extractor "${extractor::class.simpleName}" is likely bugged: + 1. the set of labels $names does not match the keys ${data.keys}, but iteration may fail as + 2. it returned a map with non-predictable iteration order of type ${data::class.simpleName}" + """.trimIndent(), + ) + } + data.values.joinToString(" ") } } + } outputPrintStream.println(line) } diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt index d26d269e56..f39778df8c 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DSLLoader.kt @@ -54,6 +54,11 @@ internal class DSLLoader, I : Incarnation>( var theEnvironment: Environment = EmptyEnvironment(incarnation) val exporters = mutableListOf>() val monitors = mutableListOf>() + val instancedVariables: Map by lazy { + variables.mapValues { + values.getOrDefault(it.key, it.value.default) + } + } context(incarnation) { object : SimulationContext { @@ -150,7 +155,7 @@ internal class DSLLoader, I : Incarnation>( } ReadOnlyProperty { _, _ -> @Suppress("UNCHECKED_CAST") - values.getOrDefault(property.name, registeredVariable.default) as V + instancedVariables[property.name] as V } } @@ -169,6 +174,9 @@ internal class DSLLoader, I : Incarnation>( The available variables are: ${variables.keys} """.trimIndent() } + exporters.forEach { exporter -> + exporter.bindVariables(instancedVariables) + } val theSimulation: Simulation = Engine(theEnvironment) if (exporters.isNotEmpty()) { theSimulation.addOutputMonitor(GlobalExporter(exporters)) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/LoadingSystem.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/LoadingSystem.kt index 9cd67fac25..4b53e86492 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/LoadingSystem.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/LoadingSystem.kt @@ -137,21 +137,19 @@ internal abstract class LoadingSystem(private val originalContext: Context, priv logger.debug("Deployment descriptors: {}", deploymentDescriptors) } // EXPORTS - val exporters = - SimulationModel.visitRecursively>( - context, - root.getOrEmpty(AlchemistYamlSyntax.export), - ) { - SimulationModel.visitSingleExporter(incarnation, context, it) - } + val exporters = SimulationModel.visitRecursively>( + context, + root.getOrEmpty(AlchemistYamlSyntax.export), + ) { + SimulationModel.visitSingleExporter(incarnation, context, it) + } exporters.forEach { it.bindVariables(variableValues) } // ENGINE val engineDescriptor = root[AlchemistYamlSyntax.engine] - val engine: Simulation = - SimulationModel - .visitBuilding>(context, engineDescriptor) - ?.getOrThrow() - ?: Engine(environment) + val engine: Simulation = SimulationModel + .visitBuilding>(context, engineDescriptor) + ?.getOrThrow() + ?: Engine(environment) // Attach monitors monitors.forEach(engine::addOutputMonitor) // Attach data exporters diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt index 59f178f6dd..91d77fb7cd 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/loader/SimulationModel.kt @@ -611,7 +611,6 @@ internal object SimulationModel { exporter.bindDataExtractors(dataExtractors) Result.success(exporter) } - else -> null } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt index 1a4d56a033..0914eb471d 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt @@ -58,6 +58,7 @@ class KotlinDslProviderTest { Arguments.of("dsl/kts/14-exporters.alchemist.kts", "dsl/yml/14-exporters.yml"), Arguments.of("dsl/kts/15-variables.alchemist.kts", "dsl/yml/15-variables.yml"), Arguments.of("dsl/kts/18-properties.alchemist.kts", "dsl/yml/18-properties.yml"), + Arguments.of("dsl/kts/19-performance.alchemist.kts", "dsl/yml/19-performance.yml"), ) } } diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt deleted file mode 100644 index 7b1b713535..0000000000 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/PerformanceComparisonTest.kt +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2010-2026, Danilo Pianini and contributors - * listed, for each module, in the respective subproject's build.gradle.kts file. - * - * This file is part of Alchemist, and is distributed under the terms of the - * GNU General Public License, with a linking exception, - * as described in the file LICENSE in the Alchemist distribution's top directory. - */ - -package it.unibo.alchemist.boundary.kotlindsl - -import it.unibo.alchemist.boundary.LoadAlchemist -import it.unibo.alchemist.boundary.Loader -import it.unibo.alchemist.boundary.kotlindsl.TestComparators.shouldEqual -import it.unibo.alchemist.model.Position -import java.io.ByteArrayOutputStream -import java.io.File -import java.io.PrintStream -import java.util.Locale -import kotlin.time.measureTime -import org.junit.jupiter.api.Assertions.assertNotNull -import org.junit.jupiter.api.Test -import org.kaikikm.threadresloader.ResourceLoader - -class PerformanceComparisonTest { - - private data class PerformanceStats( - val yamlLoadingTime: Long, - val dslLoadingTime: Long, - val avgYamlActionTime: Double, - val avgDslActionTime: Double, - val minYamlActionTime: Long, - val minDslActionTime: Long, - val maxYamlActionTime: Long, - val maxDslActionTime: Long, - ) - - private fun calculateStats( - yamlLoadingTime: Long, - dslLoadingTime: Long, - yamlActionTimes: List, - dslActionTimes: List, - ): PerformanceStats = PerformanceStats( - yamlLoadingTime = yamlLoadingTime, - dslLoadingTime = dslLoadingTime, - avgYamlActionTime = yamlActionTimes.average(), - avgDslActionTime = dslActionTimes.average(), - minYamlActionTime = yamlActionTimes.minOrNull() ?: 0L, - minDslActionTime = dslActionTimes.minOrNull() ?: 0L, - maxYamlActionTime = yamlActionTimes.maxOrNull() ?: 0L, - maxDslActionTime = dslActionTimes.maxOrNull() ?: 0L, - ) - - private fun printResults(header: String, stats: PerformanceStats) { - println("\n=== $header ===") - println("YAML Loader:") - println(" Loading Phase:") - println(" Time: ${stats.yamlLoadingTime} ms") - println(" Action Phase:") - println(" Average: ${String.format(Locale.US, "%.2f", stats.avgYamlActionTime)} ms") - println(" Min: ${stats.minYamlActionTime} ms") - println(" Max: ${stats.maxYamlActionTime} ms") - println( - " Total Average: ${String.format( - Locale.US, - "%.2f", - stats.yamlLoadingTime + stats.avgYamlActionTime, - )} ms", - ) - println("\nDSL Loader:") - println(" Loading Phase:") - println(" Time: ${stats.dslLoadingTime} ms") - println(" Action Phase:") - println(" Average: ${String.format(Locale.US, "%.2f", stats.avgDslActionTime)} ms") - println(" Min: ${stats.minDslActionTime} ms") - println(" Max: ${stats.maxDslActionTime} ms") - println( - " Total Average: ${String.format(Locale.US, "%.2f", stats.dslLoadingTime + stats.avgDslActionTime)} ms", - ) - } - - private fun printSpeedup(stats: PerformanceStats, dslFasterMsg: String, yamlFasterMsg: String) { - val totalYamlTime = stats.yamlLoadingTime + stats.avgYamlActionTime - val totalDslTime = stats.dslLoadingTime + stats.avgDslActionTime - val speedup = totalYamlTime / totalDslTime - println("\nSpeedup (Total): ${String.format(Locale.US, "%.2f", speedup)}x") - if (speedup > 1.0) { - println("$dslFasterMsg ${String.format(Locale.US, "%.2f", speedup)}x faster than YAML") - } else { - println("$yamlFasterMsg ${String.format(Locale.US, "%.2f", 1.0 / speedup)}x faster than DSL") - } - val loadingSpeedup = stats.yamlLoadingTime.toDouble() / stats.dslLoadingTime.toDouble() - println("Loading Phase Speedup: ${String.format(Locale.US, "%.2f", loadingSpeedup)}x") - val actionSpeedup = stats.avgYamlActionTime / stats.avgDslActionTime - println("Action Phase Speedup: ${String.format(Locale.US, "%.2f", actionSpeedup)}x") - } - - private fun runPerformanceTest( - testHeader: String, - yamlResource: String, - dslResource: String, - iterations: Int, - resultsHeader: String, - dslFasterMsg: String, - yamlFasterMsg: String, - yamlLoaderAction: (Loader) -> Unit, - dslLoaderAction: (Loader) -> Unit, - ): PerformanceStats { - val originalOut = System.out - val originalErr = System.err - val nullStream = PrintStream(ByteArrayOutputStream()) - println("\n=== $testHeader ===") - println("Resource: $yamlResource") - println("Iterations: $iterations\n") - val yamlActionTimes = mutableListOf() - val dslActionTimes = mutableListOf() - val dslUrl = ResourceLoader.getResource(dslResource)!! - val ymlUrl = ResourceLoader.getResource(yamlResource)!! - System.setOut(nullStream) - System.setErr(nullStream) - var yamlLoader: Loader? = null - val yamlLoadingTime = measureTime { - yamlLoader = LoadAlchemist.from(ymlUrl) - } - assertNotNull(yamlLoader) - var dslLoader: Loader? = null - val dslLoadingTime = measureTime { - dslLoader = LoadAlchemist.from(dslUrl) - } - assertNotNull(dslLoader) - System.setOut(originalOut) - System.setErr(originalErr) - repeat(iterations) { - System.setOut(nullStream) - System.setErr(nullStream) - val yamlActionTime = measureTime { - yamlLoaderAction(yamlLoader!!) - } - val dslActionTime = measureTime { - dslLoaderAction(dslLoader!!) - } - System.setOut(originalOut) - System.setErr(originalErr) - yamlActionTimes.add(yamlActionTime.inWholeMilliseconds) - dslActionTimes.add(dslActionTime.inWholeMilliseconds) - } - val stats = calculateStats( - yamlLoadingTime.inWholeMilliseconds, - dslLoadingTime.inWholeMilliseconds, - yamlActionTimes, - dslActionTimes, - ) - printResults(resultsHeader, stats) - printSpeedup(stats, dslFasterMsg, yamlFasterMsg) - println("\n=== Test completed ===\n") - return stats - } - private fun runTestWith( - name: String, - action: (Loader) -> Unit, - testName: String, - iterations: Int = 10, - ): PerformanceStats { - val dslResource = "dsl/kts/$name.alchemist.kts" - val yamlResource = "dsl/yml/$name.yml" - return runPerformanceTest( - testHeader = testName, - yamlResource = yamlResource, - dslResource = dslResource, - iterations = iterations, - resultsHeader = "Results", - dslFasterMsg = "DSL loading is", - yamlFasterMsg = "YAML loading is", - yamlLoaderAction = action, - dslLoaderAction = action, - ) - } - - @Test - fun > `performance comparison between YAML and DSL loaders`() { - runTestWith( - "19-performance", - testName = "Performance Test: YAML vs DSL Loader", - action = { it.getDefault() }, - iterations = 20, - ) - } - - @Test - fun `performance comparison - loading phase only`() { - val stats = mutableListOf() - repeat(50) { - stats += runTestWith( - "19-performance", - action = {}, - testName = "Performance Test: Loading Phase Only ", - ) - } - val avgYamlLoadingTime = stats.map { it.yamlLoadingTime }.average() - val avgDslLoadingTime = stats.map { it.dslLoadingTime }.average() - println("\n=== Loading Phase Only Average Results ===") - println( - "YAML Loader Average Loading Time: ${String.format( - Locale.US, - "%.2f", - avgYamlLoadingTime, - )} ms", - ) - println( - "DSL Loader Average Loading Time: ${String.format( - Locale.US, - "%.2f", - avgDslLoadingTime, - )} ms", - ) - } - - @Test - fun `verify both loaders produce equivalent results`() { - val yamlResource = "dsl/yml/19-performance.yml" - val dslResource = "/dsl/kts/19-performance.alchemist.kts" - val dslUrl = requireNotNull(this.javaClass.getResource(dslResource)) { - "Resource $dslResource not found on test classpath" - } - val dslFile = File(dslUrl.toURI()) - val yamlLoader = LoadAlchemist.from(ResourceLoader.getResource(yamlResource)!!) - val dslLoader = LoadAlchemist.from(dslFile) - assertNotNull(yamlLoader) - assertNotNull(dslLoader) - dslLoader.shouldEqual(yamlResource, 0L) - } -} diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt index 28fa49f38a..74e712d7e1 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/TestVariables.kt @@ -80,9 +80,9 @@ class TestVariables { deployments { deploy(point(0.0, 0.0)) { contents { - -"mSize" to mSize - -"sourceStart" to sourceStart - -"sourceSize" to sourceSize + "mSize"(mSize) + "sourceStart"(sourceStart) + "sourceSize"(sourceSize) } } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts index 94ec000c0e..b926084b51 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/12-layers.alchemist.kts @@ -7,7 +7,6 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ package dsl.kts -import it.unibo.alchemist.boundary.kotlindsl.ContentContext.unaryMinus import it.unibo.alchemist.boundary.kotlindsl.environment import it.unibo.alchemist.boundary.kotlindsl.simulation2D @@ -18,7 +17,7 @@ simulation2D(ProtelisIncarnation()) { deployments { deploy(grid(-5.0, -5.0, 5.0, 5.0, 0.25, 0.1, 0.1)) { contents { - -just("a") + -"a" } } } diff --git a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts index c83ff4fdfc..58d0b3b663 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/15-variables.alchemist.kts @@ -22,7 +22,6 @@ simulation2D(SAPEREIncarnation()) { val mSize = -size val sourceStart = mSize / 10.0 val sourceSize = size / 5.0 - terminator(AfterTime(DoubleTime(1.0))) networkModel(ConnectWithinDistance(0.5)) deployments { deploy(makePerturbedGridForTesting()) { diff --git a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts index 2bcee3a77b..5f3f062cd6 100644 --- a/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts +++ b/alchemist-loading/src/test/resources/dsl/kts/19-performance.alchemist.kts @@ -25,9 +25,6 @@ simulation2D(SAPEREIncarnation()) { val mSize = -size val sourceStart = mSize / 10.0 val sourceSize = size / 5.0 - layer("A", StepLayer(2.0, 2.0, concentrationOf(100.0), concentrationOf(0.0))) - layer("B", StepLayer(-2.0, -2.0, concentrationOf(0.0), concentrationOf(100.0))) - layer("C", StepLayer(0.0, 0.0, concentrationOf(50.0), concentrationOf(50.0))) monitor(SimpleMonitor()) deployments { deploy(circle(200, 0.0, 0.0, 20.0)) { @@ -36,8 +33,8 @@ simulation2D(SAPEREIncarnation()) { if (position in Rectangle(-5.0, -5.0, 10.0, 10.0)) { - "centermolecule" } - program("1", 1.0) - program("2", 2.0) } + program("{basemolecule} --> {processed}", 1.0) + program("{processed} --> +{basemolecule}") } } deploy(grid(mSize, mSize, size, size, 0.25, 0.25, 0.1, 0.1)) { contents { diff --git a/alchemist-loading/src/test/resources/dsl/yml/19-performance.yml b/alchemist-loading/src/test/resources/dsl/yml/19-performance.yml index 74068e27e3..6e0f1d2fbc 100644 --- a/alchemist-loading/src/test/resources/dsl/yml/19-performance.yml +++ b/alchemist-loading/src/test/resources/dsl/yml/19-performance.yml @@ -26,17 +26,6 @@ variables: sourceSize: &sourceSize formula: size / 5 -layers: - - type: StepLayer - parameters: [2, 2, 100, 0] - molecule: A - - type: StepLayer - parameters: [-2, -2, 0, 100] - molecule: B - - type: StepLayer - parameters: [0, 0, 50, 50] - molecule: C - monitors: - type: another.location.SimpleMonitor diff --git a/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/Assertions.kt b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/Assertions.kt new file mode 100644 index 0000000000..1d4596127e --- /dev/null +++ b/alchemist-test/src/main/kotlin/it/unibo/alchemist/test/Assertions.kt @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2010-2026, Danilo Pianini and contributors + * listed, for each module, in the respective subproject's build.gradle.kts file. + * + * This file is part of Alchemist, and is distributed under the terms of the + * GNU General Public License, with a linking exception, + * as described in the file LICENSE in the Alchemist distribution's top directory. + */ + +package it.unibo.alchemist.test + +import it.unibo.alchemist.boundary.OutputMonitor +import it.unibo.alchemist.core.Simulation +import it.unibo.alchemist.model.Action +import it.unibo.alchemist.model.Actionable +import it.unibo.alchemist.model.Condition +import it.unibo.alchemist.model.Environment +import it.unibo.alchemist.model.LinkingRule +import it.unibo.alchemist.model.Node +import it.unibo.alchemist.model.NodeProperty +import it.unibo.alchemist.model.Position +import it.unibo.alchemist.model.Time +import it.unibo.alchemist.model.TimeDistribution +import it.unibo.alchemist.test.AlchemistTesting.runInCurrentThread +import java.util.concurrent.CyclicBarrier +import java.util.concurrent.TimeUnit +import kotlin.test.assertContentEquals +import org.junit.jupiter.api.Assertions.assertEquals + +private fun Iterable.ebeEquals(other: Iterable, elementComparator: (T, T) -> Unit) { + val thisList = this.toList() + val otherList = other.toList() + assertEquals(otherList.size, thisList.size) + otherList.zip(thisList).forEach { (expected, actual) -> + elementComparator(expected, actual) + } +} + +infix fun Condition<*>.shouldEqual(other: Condition<*>) { + assertEquals(other::class, this::class, "Condition types don't match") + assertEquals(other.context, context, "Condition contexts don't match") + assertEquals(other.isValid, isValid, "Condition validity doesn't match") + assertEquals(other.propensityContribution, propensityContribution) + assertEquals(other.inboundDependencies, inboundDependencies) +} + +infix fun Action<*>.shouldEqual(other: Action<*>) { + assertEquals(other::class, this::class, "Action types don't match") + assertEquals(other.context, context, "Action contexts don't match") + assertEquals(other.outboundDependencies, outboundDependencies) +} + +infix fun TimeDistribution<*>.shouldEqual(other: TimeDistribution<*>) { + assertEquals(other::class, this::class, "TimeDistribution types don't match") + assertEquals(other.rate, rate) + assertEquals(other.nextOccurence, nextOccurence) +} + +infix fun Actionable<*>.shouldEqual(other: Actionable<*>) { + assertEquals(other::class, this::class, "Actionable types don't match") + assertEquals(other.inboundDependencies, inboundDependencies) + assertEquals(other.outboundDependencies, outboundDependencies) + assertEquals(other.rate, rate) + assertEquals(other.tau, tau) + timeDistribution shouldEqual other.timeDistribution + conditions.ebeEquals(other.conditions) { expected, actual -> actual shouldEqual expected } + actions.ebeEquals(other.actions) { expected, actual -> actual shouldEqual expected } +} + +infix fun NodeProperty<*>.shouldEqual(other: NodeProperty<*>) { + assertEquals(other::class, this::class, "NodeProperty types don't match") +} + +infix fun Node<*>.shouldEqual(other: Node<*>) { + assertEquals(other.id, id) + assertEquals(other.moleculeCount, moleculeCount) + assertEquals(other.contents, contents) + assertEquals(other.properties.size, properties.size) + properties.ebeEquals(other.properties) { expected, actual -> actual shouldEqual expected } + reactions.ebeEquals(other.reactions) { expected, actual -> actual shouldEqual expected } +} + +infix fun LinkingRule<*, *>.shouldEqual(other: LinkingRule<*, *>) { + assertEquals(other::class, this::class, "LinkingRule types don't match") + assertEquals(other.isLocallyConsistent, isLocallyConsistent) +} + +infix fun > Environment.shouldEqual(other: Environment) { + assertEquals(other::class, this::class, "Environment types don't match") + assertContentEquals(other.size, size, "Environment sizes don't match") + assertContentEquals(other.sizeInDistanceUnits, sizeInDistanceUnits) + assertEquals(other.incarnation::class, incarnation::class) + assertEquals(other.dimensions, dimensions) + assertEquals(other.isTerminated, isTerminated) + assertContentEquals(other.sizeInDistanceUnits, sizeInDistanceUnits) + linkingRule shouldEqual other.linkingRule + val positions = nodes.sortedBy { it.id }.map { getPosition(it) } + val otherPositions = other.sortedBy { it.id }.map { getPosition(it) } + positions.ebeEquals(otherPositions) { expected, actual -> assertEquals(expected, actual) } + nodes.ebeEquals(other.nodes) { expected, actual -> + actual shouldEqual expected + } + globalReactions.ebeEquals(other.globalReactions) { expected, actual -> actual shouldEqual expected } + layers.toList().sortedBy { (molecule, _) -> molecule.toString() }.ebeEquals( + other.layers.toList().sortedBy { (molecule, _) -> molecule.toString() }, + ) { expected, actual -> + assertEquals(expected.first, actual.first, "Layer molecules don't match") + positions.forEach { position -> + assertEquals( + expected.second.getValue(position), + actual.second.getValue(position), + "Layer values at position $position don't match", + ) + } + } +} + +fun > Simulation.equalsForSteps(other: Simulation, steps: Long) { + assertEquals(other::class, this::class, "Simulation types don't match") + outputMonitors.sortedBy { + it::class.simpleName + }.ebeEquals(other.outputMonitors.sortedBy { it::class.simpleName }) { expected, actual -> + assertEquals(expected::class, actual::class, "OutputMonitor types don't match") + } + val expectedThread = Thread(null, other, "Alchemist-Test-Expected") + val actualThread = Thread.currentThread() + val syncMonitor = object : OutputMonitor { + val barrier = CyclicBarrier(2) + override fun stepDone(environment: Environment, reaction: Actionable?, time: Time, step: Long) { + barrier.await(1, TimeUnit.SECONDS) + if (barrier.isBroken) { + error("Barrier broken while waiting for step $step to complete") + } + if (Thread.currentThread() == actualThread) { + assertEquals(other.time, this@equalsForSteps.time) + assertEquals(other.step, this@equalsForSteps.step) + this@equalsForSteps.environment shouldEqual other.environment + } + if (environment.simulation.step >= steps) { + environment.simulation.terminate() + } + barrier.await(1, TimeUnit.SECONDS) + } + } + addOutputMonitor(syncMonitor) + other.addOutputMonitor(syncMonitor) + expectedThread.start() + other.play() + runInCurrentThread() + error.map { throw it } + other.error.map { throw it } +} From 52bb68e680430d9d77f51e95467c45ced5441370 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 15 Feb 2026 19:24:14 +0100 Subject: [PATCH 193/196] docs: add documentation for Alchemist script execution entry point --- .../alchemist/kotlinscript/AlchemistScriptHost.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt index 331a7d6821..a8ee4c4729 100644 --- a/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt +++ b/alchemist-kotlinscript/src/main/kotlin/it/unibo/alchemist/kotlinscript/AlchemistScriptHost.kt @@ -18,6 +18,18 @@ import kotlin.script.experimental.api.valueOrNull import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost +/** + * Host entry point for executing an Alchemist Kotlin script. + * + * The application expects exactly one command-line argument: the path to a + * Kotlin script file (usually with extension `.alchemist.kts`) that evaluates to + * an instance of [Loader]. The returned loader's launcher will be used to + * launch the simulation. + * + * @param args command-line arguments; must contain exactly one element which is + * the path to the script file to execute. + * @throws IllegalArgumentException if the number of arguments is not exactly one. + */ fun main(vararg args: String) { require(args.size == 1) { "usage: " } @@ -29,11 +41,9 @@ fun main(vararg args: String) { // jvm { mainArguments(scriptArgs) } }, ) - result.reports .filter { it.severity > ScriptDiagnostic.Severity.DEBUG } .forEach { d -> System.err.println("${d.severity}: ${d.message}") } - val eval = result.valueOrNull() val returned = (eval?.returnValue as? ResultValue.Value)?.value check(returned is Loader) { From e9675d046a609725cee332547874940553e03e53 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 15 Feb 2026 20:25:36 +0100 Subject: [PATCH 194/196] fix: improve exclusion logic for Detekt tasks in build.gradle.kts --- build.gradle.kts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 46ead42c91..dcaf7b7a20 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -77,7 +77,9 @@ allprojects { tasks.withType().configureEach { exclude { fileTree -> val absolutePath = fileTree.file.absolutePath - listOf("/build/", "/generated/").any { it in absolutePath } + listOf("build", "generated") + .map { "${File.separator}$it${File.separator}" } + .any { it in absolutePath } } } From 2b39344051871da0f4e3f8738c7c1576feb51a0c Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 15 Feb 2026 21:16:07 +0100 Subject: [PATCH 195/196] test: reduce steps in LoadAlchemist test for efficiency --- .../unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt index 0914eb471d..9e320a8aa4 100644 --- a/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt +++ b/alchemist-loading/src/test/kotlin/it/unibo/alchemist/boundary/kotlindsl/KotlinDslProviderTest.kt @@ -48,7 +48,7 @@ class KotlinDslProviderTest { val url = requireNotNull(ResourceLoader.getResource(ktsResource)) { "Resource $ktsResource not found on test classpath" } - LoadAlchemist.from(url).shouldEqual(ymlResource, steps = 10_000L) + LoadAlchemist.from(url).shouldEqual(ymlResource, steps = 100L) } companion object { From 16e24e127d2a92c49ddd4788cd1c7d36548d63c5 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 15 Feb 2026 21:58:18 +0100 Subject: [PATCH 196/196] refactor: remove unnecessary suppression annotations and clean up code --- .../geometry/TestEuclidean2DTransformation.kt | 31 ++++---------- .../TestEuclidean2DShapeFactory.kt | 42 ++++++++----------- .../model/environments/AbstractEnvironment.kt | 1 - .../MoleculeControlledTimeDistribution.kt | 1 - .../SimpleNetworkArrivals.kt | 7 ++-- .../model/incarnations/ProtelisIncarnation.kt | 7 +--- .../protelis/AlchemistExecutionContext.kt | 4 -- .../model/incarnations/ScafiIncarnation.scala | 20 +++------ .../boundary/kotlindsl/ActionableContext.kt | 2 - .../boundary/kotlindsl/DeploymentContext.kt | 4 +- .../boundary/kotlindsl/DeploymentsContext.kt | 2 - .../boundary/kotlindsl/EnvironmentContext.kt | 2 - .../kotlindsl/SimulationContextExtensions.kt | 3 -- .../boundary/kotlindsl/TerminatorsContext.kt | 2 - .../kotlindsl/TimeDistributionContext.kt | 2 - .../actions/HeadTowardRandomDirection.kt | 3 -- buildSrc/src/main/kotlin/Libs.kt | 1 - 17 files changed, 38 insertions(+), 96 deletions(-) diff --git a/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/interfaces/geometry/TestEuclidean2DTransformation.kt b/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/interfaces/geometry/TestEuclidean2DTransformation.kt index bc068953ec..f530e36957 100644 --- a/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/interfaces/geometry/TestEuclidean2DTransformation.kt +++ b/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/interfaces/geometry/TestEuclidean2DTransformation.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.interfaces.geometry -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import io.kotest.core.spec.style.FreeSpec import io.kotest.matchers.shouldBe import it.unibo.alchemist.model.geometry.Euclidean2DShapeFactory @@ -22,36 +21,24 @@ import it.unibo.alchemist.model.positions.Euclidean2DPosition private val factory: Euclidean2DShapeFactory = GeometricShapeFactory.getInstance() -@SuppressFBWarnings("SE_BAD_FIELD_STORE") class TestEuclidean2DTransformation : FreeSpec({ "Test origin" - { - factory - .oneOfEachWithSize(1.0) + factory.oneOfEachWithSize(1.0) .filter { it.value !is AdimensionalShape } .forEach { it.key { - var shape = - it.value.transformed { - origin(0.0, 0.0) - } + var shape = it.value.transformed { origin(0.0, 0.0) } val reference = shape.centroid - shape = - shape.transformed { - origin(0.0, 0.0) - } + shape = shape.transformed { origin(0.0, 0.0) } reference.distanceTo(shape.centroid) shouldBe 0.0 - shape = - shape.transformed { - origin(0.0, 10.0) - } + shape = shape.transformed { origin(0.0, 10.0) } reference.distanceTo(shape.centroid) shouldBe 10.0 - shape = - shape.transformed { - origin(10.0, 10.0) - origin(3.0, 3.0) - origin(6.0, 0.0) - } + shape = shape.transformed { + origin(10.0, 10.0) + origin(3.0, 3.0) + origin(6.0, 0.0) + } reference.distanceTo(shape.centroid) shouldBe 6.0 } } diff --git a/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/interfaces/geometry/euclidean2d/TestEuclidean2DShapeFactory.kt b/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/interfaces/geometry/euclidean2d/TestEuclidean2DShapeFactory.kt index 2e28d901b9..0733a39da3 100644 --- a/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/interfaces/geometry/euclidean2d/TestEuclidean2DShapeFactory.kt +++ b/alchemist-euclidean-geometry/src/test/kotlin/it/unibo/alchemist/model/interfaces/geometry/euclidean2d/TestEuclidean2DShapeFactory.kt @@ -1,6 +1,5 @@ package it.unibo.alchemist.model.interfaces.geometry.euclidean2d -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FreeSpec @@ -26,7 +25,6 @@ private val fakeShape = override fun transformed(transformation: Euclidean2DTransformation.() -> Unit) = this } -@SuppressFBWarnings("SE_BAD_FIELD_STORE") class TestEuclidean2DShapeFactory : FreeSpec({ /* @@ -36,11 +34,10 @@ class TestEuclidean2DShapeFactory : */ "!Shape.intersect symmetry" - { val firsts = factory.oneOfEachWithSize(DEFAULT_SHAPE_SIZE) - val seconds = - firsts.mapValues { - // puts the other shapes in a corner to test "edge" cases - it.value.transformed { origin(DEFAULT_SHAPE_SIZE * 2, DEFAULT_SHAPE_SIZE * 2) } - } + val seconds = firsts.mapValues { + // puts the other shapes in a corner to test "edge" cases + it.value.transformed { origin(DEFAULT_SHAPE_SIZE * 2, DEFAULT_SHAPE_SIZE * 2) } + } val names = firsts.keys.toList() for (f in names.indices) { for (s in f until names.size) { @@ -55,9 +52,7 @@ class TestEuclidean2DShapeFactory : "Test requireCompatible" { shouldNotThrowAny { - factory - .oneOfEachWithSize(DEFAULT_SHAPE_SIZE) - .values + factory.oneOfEachWithSize(DEFAULT_SHAPE_SIZE).values .forEach { factory.requireCompatible(it) } } shouldThrow { @@ -74,20 +69,19 @@ class TestEuclidean2DShapeFactory : val angle = Math.PI / 4 val initialOrigin = Euclidean2DPosition(100.0, 100.0) val shape = it.value.transformed { origin(initialOrigin) } - val rotated = - shape - .transformed { rotate(angle) } - .transformed { origin(500.0, 500.0) } - .transformed { rotate(angle) } - .transformed { origin(0.0, 0.0) } - .transformed { rotate(angle) } - .transformed { origin(7.0, 0.0) } - .transformed { rotate(angle) } - .transformed { repeat(3) { rotate(angle) } } - .transformed { - origin(initialOrigin) - rotate(angle) - } + val rotated = shape + .transformed { rotate(angle) } + .transformed { origin(500.0, 500.0) } + .transformed { rotate(angle) } + .transformed { origin(0.0, 0.0) } + .transformed { rotate(angle) } + .transformed { origin(7.0, 0.0) } + .transformed { rotate(angle) } + .transformed { repeat(3) { rotate(angle) } } + .transformed { + origin(initialOrigin) + rotate(angle) + } rotated.centroid shouldBe shape.centroid } } diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt index d87c77c006..ea1f7da744 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/environments/AbstractEnvironment.kt @@ -171,7 +171,6 @@ abstract class AbstractEnvironment> protected constructor( private fun getAllNodesInRange(center: P, range: Double): List> { require(range > 0) { "Range query must be positive (provided: $range)" } - @Suppress("UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS") val validCache = cache ?: Caffeine.newBuilder() .maximumSize(1000) .build, List>> { (pos, r) -> runQuery(pos, r) } diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/MoleculeControlledTimeDistribution.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/MoleculeControlledTimeDistribution.kt index fead3e8aa0..3612bbde85 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/MoleculeControlledTimeDistribution.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/MoleculeControlledTimeDistribution.kt @@ -50,7 +50,6 @@ constructor( ) : AnyRealDistribution( start, - @Suppress("OVERRIDE_DEPRECATION") object : RealDistribution { /* * Unknown values diff --git a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/SimpleNetworkArrivals.kt b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/SimpleNetworkArrivals.kt index ee03bab5d6..776b7f4462 100644 --- a/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/SimpleNetworkArrivals.kt +++ b/alchemist-implementationbase/src/main/kotlin/it/unibo/alchemist/model/timedistributions/SimpleNetworkArrivals.kt @@ -15,7 +15,6 @@ import it.unibo.alchemist.model.Molecule import it.unibo.alchemist.model.Node import it.unibo.alchemist.model.Time import it.unibo.alchemist.model.times.DoubleTime -import java.lang.IllegalStateException /** * This class models a distribution that follows the packet arrival times as described in @@ -167,8 +166,10 @@ class SimpleNetworkArrivals private constructor( } ?: bw } - /** Computes the packet size, defaulting to 1.0 if not specified or invalid. */ - @Suppress("UnreachableCode") // Detekt false positive. Remove once fixed. + /** + * Computes the packet size from constants or properties. + * Defaults to 1.0 if not specified or invalid. + */ val packetSize: Double get() = constantPacketSize ?: incarnation.getProperty(node, packetSizeMolecule, packetSizeProperty).takeIf { it.isFinite() && it >= 0 } diff --git a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt index 90042c67f6..d3a759834c 100644 --- a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt +++ b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/incarnations/ProtelisIncarnation.kt @@ -12,7 +12,6 @@ package it.unibo.alchemist.model.incarnations import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheLoader import com.google.common.cache.LoadingCache -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Actionable import it.unibo.alchemist.model.Condition @@ -299,11 +298,7 @@ class ProtelisIncarnation

> : Incarnation { * * @param node the [Node] */ - class ProtectedExecutionEnvironment - @SuppressFBWarnings(value = ["EI_EXPOSE_REP2"], justification = "This is intentional") - constructor( - private val node: Node<*>, - ) : ExecutionEnvironment { + class ProtectedExecutionEnvironment(private val node: Node<*>) : ExecutionEnvironment { private val shadow: ExecutionEnvironment = SimpleExecutionEnvironment() override fun commit() = Unit diff --git a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/AlchemistExecutionContext.kt b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/AlchemistExecutionContext.kt index e28211771b..51376a3d71 100644 --- a/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/AlchemistExecutionContext.kt +++ b/alchemist-incarnation-protelis/src/main/kotlin/it/unibo/alchemist/model/protelis/AlchemistExecutionContext.kt @@ -12,7 +12,6 @@ package it.unibo.alchemist.model.protelis import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheLoader import com.google.common.hash.Hashing -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import it.unibo.alchemist.model.Environment import it.unibo.alchemist.model.GeoPosition import it.unibo.alchemist.model.Molecule @@ -166,7 +165,6 @@ class AlchemistExecutionContext

>( override fun getCurrentTime() = reaction.tau.toDouble() - @SuppressFBWarnings(value = ["EI_EXPOSE_REP"], justification = INTENTIONAL) override fun getDeviceUID(): DeviceUID = protelisDevice override fun hashCode(): Int { @@ -304,7 +302,5 @@ class AlchemistExecutionContext

>( * It only makes sense in case the environment is a [MapEnvironment] */ val APPROXIMATE_NBR_RANGE: Molecule = SimpleMolecule("APPROXIMATE_NBR_RANGE") - - private const val INTENTIONAL = "This is intentional" } } diff --git a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala index e5bddf6ee9..6683e51a0e 100644 --- a/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala +++ b/alchemist-incarnation-scafi/src/main/scala/it/unibo/alchemist/model/incarnations/ScafiIncarnation.scala @@ -89,13 +89,13 @@ sealed class ScafiIncarnation[T, P <: Position[P]] extends Incarnation[T, P] { } ) - /** NOTE: String v may be prefixed by "_" symbol to avoid caching the value resulting from its interpretation */ + /** NOTE: String v may be prefixed by the "_" symbol to avoid caching the value resulting from its interpretation */ override def createConcentration(data: Any): T = { /* * TODO: support double-try parse in case of strings (to avoid "\"string\"" in the YAML file) */ val dataString = data.toString - val doCacheValue = !dataString.startsWith("_"); + val doCacheValue = !dataString.startsWith("_") CachedInterpreter[AnyRef](if (doCacheValue) dataString else dataString.tail, doCacheValue).asInstanceOf[T] } @@ -187,7 +187,7 @@ sealed class ScafiIncarnation[T, P <: Position[P]] extends Incarnation[T, P] { val frequency = toDouble(parameters) if (frequency.isNaN) { throw new IllegalArgumentException( - parameters + " is not a valid number, the time distribution could not be created." + parameters.toString + " is not a valid number, the time distribution could not be created." ) } new DiracComb(new DoubleTime(randomGenerator.nextDouble() / frequency), frequency) @@ -211,9 +211,7 @@ object ScafiIncarnationUtils { body(node.asProperty(classOf[ScafiDevice[T]])) } - def runOnlyOnScafiDevice[T, A](node: Node[T], message: String)(body: => A): A = - runInScafiDeviceContext(node, message, (_: ScafiDevice[T]) => body) - def isScafiNode[T](node: Node[T]): Boolean = node.asPropertyOrNull[ScafiDevice[T]](classOf[ScafiDevice[T]]) != null + private def isScafiNode[T](node: Node[T]): Boolean = node.asPropertyOrNull[ScafiDevice[T]](classOf[ScafiDevice[T]]) != null def allActions[T, P <: Position[P], C](node: Node[T], klass: Class[C]): mutable.Buffer[C] = for { @@ -221,7 +219,7 @@ object ScafiIncarnationUtils { action: Action[T] <- reaction.getActions.asScala if klass.isInstance(action) } yield action.asInstanceOf[C] - def allScafiProgramsFor[T, P <: Position[P]](node: Node[T]) = + def allScafiProgramsFor[T, P <: Position[P]](node: Node[T]): mutable.Buffer[RunScafiProgram[T, P]] = allActions[T, P, RunScafiProgram[T, P]](node, classOf[RunScafiProgram[T, P]]) def allConditionsFor[T](node: Node[T], conditionClass: Class[_]): mutable.Buffer[Condition[T]] = @@ -230,14 +228,6 @@ object ScafiIncarnationUtils { condition <- reaction.getConditions.asScala if conditionClass.isInstance(condition) } yield condition - def inboundDependencies[T](node: Node[T], conditionClass: Class[_]): mutable.Buffer[Dependency] = - for { - c <- allConditionsFor(node, conditionClass) - dep <- c.getInboundDependencies.iterator().asScala - } yield dep - - def allCompletedScafiProgram[T](node: Node[T], conditionClass: Class[_]): mutable.Buffer[Dependency] = - inboundDependencies(node, classOf[ScafiComputationalRoundComplete[T]]) } object CachedInterpreter { diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ActionableContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ActionableContext.kt index 78a274203c..44dbed682e 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ActionableContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/ActionableContext.kt @@ -13,8 +13,6 @@ import it.unibo.alchemist.model.Condition * Both [action] and [condition] mutate the current [Actionable] by appending the provided element to its internal * collections. Ordering is preserved and duplicates are allowed. */ -// TODO: Detekt false positive. Remove once Detekt supports context parameters. -@Suppress("UndocumentedPublicFunction") object ActionableContext { /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt index cdb35dcfe6..38be43c3c3 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentContext.kt @@ -32,8 +32,6 @@ import org.apache.commons.math3.random.RandomGenerator * @param T the concentration type used by the simulation. * @param P the position type used by the environment. */ -// TODO: Detekt false positive. Remove once Detekt supports context parameters. -@Suppress("UndocumentedPublicFunction") interface DeploymentContext> { /** @@ -81,7 +79,7 @@ interface DeploymentContext> { fun withTimeDistribution( parameter: Any? = null, block: context(TimeDistribution) TimeDistributionContext.() -> Unit, - ) = timeDistribution>( + ) = timeDistribution( parameter as? TimeDistribution ?: makeTimeDistribution(parameter), block, ) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentsContext.kt index c77ae623e1..30a36ab4c1 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/DeploymentsContext.kt @@ -28,8 +28,6 @@ import org.apache.commons.math3.random.RandomGenerator * This interface is based on Kotlin context receivers: the relevant [RandomGenerator] and [Environment] (and, in the * overload that creates nodes via incarnation, also the [Incarnation]) must be available in the surrounding scope. */ -// TODO: Detekt false positive. Remove once Detekt supports context parameters. -@Suppress("UndocumentedPublicFunction") fun interface DeploymentsContext> { /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/EnvironmentContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/EnvironmentContext.kt index 3b3f59ccf7..9808abe362 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/EnvironmentContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/EnvironmentContext.kt @@ -38,8 +38,6 @@ import org.apache.commons.math3.random.RandomGenerator * @param T the concentration type used by the simulation. * @param P the position type used by the environment. */ -// TODO: Detekt false positive. Remove once Detekt supports context parameters. -@Suppress("UndocumentedPublicFunction") fun interface EnvironmentContext> { /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContextExtensions.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContextExtensions.kt index 55734eacf7..8d8bdcaf7f 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContextExtensions.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/SimulationContextExtensions.kt @@ -7,9 +7,6 @@ * as described in the file LICENSE in the Alchemist distribution's top directory. */ -// TODO: Detekt false positive. Remove once Detekt supports context parameters. -@file:Suppress("UndocumentedPublicFunction") - package it.unibo.alchemist.boundary.kotlindsl import it.unibo.alchemist.model.Incarnation diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt index 91f2e7f98c..4948d2e4e9 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TerminatorsContext.kt @@ -19,8 +19,6 @@ import it.unibo.alchemist.model.TerminationPredicate * This context is meant to be used with Kotlin context receivers, requiring an [Environment] to be available * in the surrounding scope. The unary minus operator provides a compact notation for adding terminators. */ -// TODO: Detekt false positive. Remove once Detekt supports context parameters. -@Suppress("UndocumentedPublicFunction") object TerminatorsContext { /** diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TimeDistributionContext.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TimeDistributionContext.kt index d2ef2dbf32..6276819caa 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TimeDistributionContext.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/boundary/kotlindsl/TimeDistributionContext.kt @@ -31,8 +31,6 @@ import org.apache.commons.math3.random.RandomGenerator * In both cases, an optional configuration block can be provided to attach [it.unibo.alchemist.model.Action]s * and [it.unibo.alchemist.model.Condition]s via [ActionableContext]. */ -// TODO: Detekt false positive. Remove once Detekt supports context parameters. -@Suppress("UndocumentedPublicFunction", "UndocumentedPublicProperty") interface TimeDistributionContext> { /** diff --git a/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/actions/HeadTowardRandomDirection.kt b/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/actions/HeadTowardRandomDirection.kt index 609242c4a6..985777b0a4 100644 --- a/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/actions/HeadTowardRandomDirection.kt +++ b/alchemist-physics/src/main/kotlin/it/unibo/alchemist/model/physics/actions/HeadTowardRandomDirection.kt @@ -9,7 +9,6 @@ package it.unibo.alchemist.model.physics.actions -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import it.unibo.alchemist.model.Action import it.unibo.alchemist.model.Context import it.unibo.alchemist.model.Node @@ -51,10 +50,8 @@ class HeadTowardRandomDirection( */ override fun getContext() = Context.LOCAL - @SuppressFBWarnings("SA_LOCAL_SELF_ASSIGNMENT") private fun Euclidean2DPosition.asAngle() = atan2(y, x) - @SuppressFBWarnings("SA_LOCAL_SELF_ASSIGNMENT") private fun Double.toDirection() = Euclidean2DPosition(cos(this), sin(this)) private companion object { diff --git a/buildSrc/src/main/kotlin/Libs.kt b/buildSrc/src/main/kotlin/Libs.kt index 3ec1b7b8ad..3372f68665 100644 --- a/buildSrc/src/main/kotlin/Libs.kt +++ b/buildSrc/src/main/kotlin/Libs.kt @@ -13,7 +13,6 @@ import kotlin.String /** * Statically defined libraries used by the project. */ -@Suppress("UndocumentedPublicProperty") object Libs { /**