From ae28f238ee277916d86d776b421d7eec3c47e135 Mon Sep 17 00:00:00 2001 From: Peva Blanchard Date: Fri, 2 Feb 2024 00:46:43 +0100 Subject: [PATCH 1/3] fix: when reducing EUnitOf: use dummy source ops --- .../core/datasource/DummySourceOperations.kt | 38 +++++++++++++++++++ .../reducer/DataExpressionReducer.kt | 18 +++++---- .../reducer/DataExpressionReducerTest.kt | 35 +++++++++++++++++ 3 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DummySourceOperations.kt diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DummySourceOperations.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DummySourceOperations.kt new file mode 100644 index 00000000..32f99c86 --- /dev/null +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/datasource/DummySourceOperations.kt @@ -0,0 +1,38 @@ +package ch.kleis.lcaac.core.datasource + +import ch.kleis.lcaac.core.lang.expression.DataExpression +import ch.kleis.lcaac.core.lang.expression.EQuantityMul +import ch.kleis.lcaac.core.lang.expression.ERecord +import ch.kleis.lcaac.core.lang.expression.EStringLiteral +import ch.kleis.lcaac.core.lang.value.* + +/* + The dummy source ops does not read from any file. + It simply returns the default record defined by the source's schema. + It is used when reducing a EUnitOf, as there is no need to fetch + an actual value from the data source, but only learn about the relevant dimension. + */ + +class DummySourceOperations : DataSourceOperations { + override fun readAll(source: DataSourceValue): Sequence> { + return sequenceOf(ERecord(source.schema.mapValues { it.value.toDataExpression() })) + } + + override fun sumProduct(source: DataSourceValue, columns: List): DataExpression { + return source.schema.filterKeys { columns.contains(it) } + .map { it.value.toDataExpression() } + .reduce { acc, dataExpression -> EQuantityMul(acc, dataExpression) } + } + + override fun getFirst(source: DataSourceValue): ERecord { + return ERecord(source.schema.mapValues { it.value.toDataExpression() }) + } + + private fun DataValue.toDataExpression(): DataExpression { + return when (this) { + is QuantityValue -> this.toEQuantityScale() + is RecordValue -> ERecord(this.entries.mapValues { it.value.toDataExpression() }) + is StringValue -> EStringLiteral(this.s) + } + } +} diff --git a/core/src/main/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducer.kt b/core/src/main/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducer.kt index b5fc3fae..275b0e15 100644 --- a/core/src/main/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducer.kt +++ b/core/src/main/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducer.kt @@ -1,6 +1,7 @@ package ch.kleis.lcaac.core.lang.evaluator.reducer import ch.kleis.lcaac.core.datasource.DataSourceOperations +import ch.kleis.lcaac.core.datasource.DummySourceOperations import ch.kleis.lcaac.core.lang.dimension.UnitSymbol import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException import ch.kleis.lcaac.core.lang.evaluator.ToValue @@ -110,14 +111,12 @@ class DataExpressionReducer( private fun reduceUnitOf(unitOf: EUnitOf): DataExpression { - with(ops) { - val reducedExpression = reduce(unitOf.expression) - return when { - reducedExpression is EQuantityScale && reducedExpression.base is EUnitLiteral -> EQuantityScale(pure(1.0), reducedExpression.base) + val reducedExpression = dummyReducer().reduce(unitOf.expression) + return when { + reducedExpression is EQuantityScale && reducedExpression.base is EUnitLiteral -> EQuantityScale(ops.pure(1.0), reducedExpression.base) - reducedExpression is EUnitOf -> reducedExpression - else -> EUnitOf(reducedExpression) - } + reducedExpression is EUnitOf -> reducedExpression + else -> EUnitOf(reducedExpression) } } @@ -251,4 +250,9 @@ class DataExpressionReducer( return if (left.scale > right.scale) left else right } + + + private fun dummyReducer(): DataExpressionReducer { + return DataExpressionReducer(dataRegister, dataSourceRegister, ops, DummySourceOperations()) + } } diff --git a/core/src/test/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducerTest.kt b/core/src/test/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducerTest.kt index b8cc1ca7..4cd540a9 100644 --- a/core/src/test/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducerTest.kt +++ b/core/src/test/kotlin/ch/kleis/lcaac/core/lang/evaluator/reducer/DataExpressionReducerTest.kt @@ -964,6 +964,41 @@ class DataExpressionReducerTest { assertEquals(expected, actual) } + @Test + fun reduce_whenUnitOf_withDataSourceExpression() { + // given + val dataSource = EDataSource( + location = "source.csv", + schema = mapOf( + "n_items" to EQuantityScale(BasicNumber(0.0), UnitFixture.unit), + "mass" to EQuantityScale(BasicNumber(0.0), UnitFixture.kg), + ) + ) + val expr = EUnitOf( + ESumProduct(EDataSourceRef("source"), listOf("n_items", "mass")) + ) + val reducer = DataExpressionReducer( + Register.empty(), + DataSourceRegister.from(mapOf( + DataSourceKey("source") to dataSource, + )), ops, sourceOps) + + + // when + val actual = reducer.reduce(expr) + + // then + val expected = EQuantityScale( + BasicNumber(1.0), + EUnitLiteral( + UnitSymbol.of("unit").multiply(UnitSymbol.of("kg")), + 1.0, + Dimension.of("none").multiply(Dimension.of("mass")) + ) + ) + assertEquals(expected, actual) + } + @Test fun reduce_whenUnitOfUnitLiteral_shouldReturnNormalForm() { // given From 8362cbfc8bfe88b9b318cae167839b25ca50f161 Mon Sep 17 00:00:00 2001 From: Peva Blanchard Date: Fri, 2 Feb 2024 14:36:57 +0100 Subject: [PATCH 2/3] fixed tutorial --- tutorials/02-language-features/05-datasources/00-datasources.lca | 1 + 1 file changed, 1 insertion(+) diff --git a/tutorials/02-language-features/05-datasources/00-datasources.lca b/tutorials/02-language-features/05-datasources/00-datasources.lca index 4df1702c..ad685b18 100644 --- a/tutorials/02-language-features/05-datasources/00-datasources.lca +++ b/tutorials/02-language-features/05-datasources/00-datasources.lca @@ -14,6 +14,7 @@ datasource inventory { the default value will be the one chosen for the entire column. */ schema { + id = "small" quantity = 1 p ram_size = 16 GB storage_size = 1 TB From 18c73c9ea9bdbee26c047fbc29d24bb6413ce24e Mon Sep 17 00:00:00 2001 From: Peva Blanchard Date: Fri, 2 Feb 2024 14:44:51 +0100 Subject: [PATCH 3/3] bump version 1.6.2 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index ef759c48..0ad28c90 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,4 @@ javaVersion=17 gradleVersion=7.6 org.gradle.jvmargs=-Xmx4096m lcaacGroup=ch.kleis.lcaac -lcaacVersion=1.6.1 +lcaacVersion=1.6.2