Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import kotlin.math.floor
*
* @author Jan Bernitt
*/
object VectorAggreation {
object VectorAggregation {

fun avg(values: DoubleArray): Double {
val sampleSize = values.size.toDouble()
Expand Down Expand Up @@ -76,19 +76,12 @@ object VectorAggreation {
return estimate(work, pivotsHeap, pos)
}

fun stddev(values: DoubleArray?): Double {
//TODO implement
return 0.0
fun stddevPop(values: DoubleArray): Double {
return kotlin.math.sqrt(variance(values, false))
}

fun stddevPop(values: DoubleArray?): Double {
//TODO implement
return 0.0
}

fun stddevSamp(values: DoubleArray?): Double {
//TODO implement
return 0.0
fun stddevSamp(values: DoubleArray): Double {
return kotlin.math.sqrt(variance(values))
}

/**
Expand All @@ -101,9 +94,12 @@ object VectorAggreation {
return values.sum()
}

fun variance(values: DoubleArray?): Double {
//TODO implement
return 0.0
fun variance(values: DoubleArray, biasCorrected: Boolean = true): Double {
val mean = values.sum() / values.size;
val meanDelta = values.map { x -> x - mean }
val meanDeltaSquared = meanDelta.map { x -> x * x }
val correction = if (biasCorrected) 1 else 0
return meanDeltaSquared.sum() / (values.size - correction)
}

private fun estimate(work: DoubleArray, pivotsHeap: IntArray, pos: Double): Double {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.hisp.dhis.lib.expression.spi
import com.ionspin.kotlin.bignum.decimal.BigDecimal
import kotlinx.datetime.*
import org.hisp.dhis.lib.expression.ast.BinaryOperator.Companion.modulo
import org.hisp.dhis.lib.expression.math.VectorAggreation
import org.hisp.dhis.lib.expression.math.VectorAggregation
import org.hisp.dhis.lib.expression.math.GS1Elements.Companion.fromKey
import org.hisp.dhis.lib.expression.math.ZScore
import kotlin.math.ceil
Expand Down Expand Up @@ -88,47 +88,48 @@ fun interface ExpressionFunctions {
Aggregate functions...
*/
fun avg(values: DoubleArray): Double {
return VectorAggreation.avg(values)
return VectorAggregation.avg(values)
}

fun count(values: DoubleArray): Double {
return VectorAggreation.count(values)
return VectorAggregation.count(values)
}

fun max(values: DoubleArray): Double {
return VectorAggreation.max(values)
return VectorAggregation.max(values)
}

fun median(values: DoubleArray): Double? {
return VectorAggreation.median(values)
return VectorAggregation.median(values)
}

fun min(values: DoubleArray): Double {
return VectorAggreation.min(values)
return VectorAggregation.min(values)
}

fun percentileCont(values: DoubleArray, fraction: Double?): Double? {
return VectorAggreation.percentileCont(values, fraction)
return VectorAggregation.percentileCont(values, fraction)
}

fun stddev(values: DoubleArray): Double {
return VectorAggreation.stddev(values)
return VectorAggregation.stddevSamp(values)
}

fun stddevPop(values: DoubleArray): Double {
return VectorAggreation.stddevPop(values)
return VectorAggregation.stddevPop(values)
}

fun stddevSamp(values: DoubleArray): Double {
return VectorAggreation.stddevSamp(values)
return VectorAggregation.stddevSamp(values)
}

fun sum(values: DoubleArray): Double {
return VectorAggreation.sum(values)
return VectorAggregation.sum(values)
}

fun variance(values: DoubleArray): Double {
return VectorAggreation.variance(values)
fun variance(values: DoubleArray): Double? {
if (values.isEmpty()) return null
return VectorAggregation.variance(values)
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.hisp.dhis.lib.expression.function
import org.hisp.dhis.lib.expression.Expression
import org.hisp.dhis.lib.expression.spi.*

abstract class AbstractAggregateFunctionTest {
abstract class AbstractVectorBasedTest {

fun evaluate(expression: String, dataValues: Map<DataItem, Any>): Double? {
return Expression(expression).evaluate(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
package org.hisp.dhis.lib.expression.function

import org.hisp.dhis.lib.expression.spi.ValueType
import org.hisp.dhis.lib.expression.util.RuleVariableValue
import kotlin.test.Test
import kotlin.test.assertEquals

/**
* Tests the `count` function
* Test of the `d2:count` function.
*
* @author Jan Bernitt
*/
internal class CountTest : AbstractAggregateFunctionTest() {
internal class CountTest : AbstractVariableBasedTest() {

@Test
fun testCount() {
val dataValues = mapOf(
newDeDataItem("u1234567890") to doubleArrayOf(0.0, 20.0, 5.0, 3.0, 7.0))
assertEquals(5.0, evaluate("count(#{u1234567890})", dataValues))
fun testCount_NoCandidates() {
val values = mapOf("v1" to RuleVariableValue(ValueType.STRING).copy(value = "value"))
assertEquals(0, evaluate("d2:count(#{v1})", values))
}

@Test
fun testCount_EmptyCandidates() {
val values = mapOf("v1" to RuleVariableValue(ValueType.STRING).copy(candidates = listOf()))
assertEquals(0, evaluate("d2:count(#{v1})", values))
}

@Test
fun testCount_Candidates() {
val values = mapOf("v1" to RuleVariableValue(ValueType.NUMBER).copy(candidates = listOf("1")))
assertEquals(1, evaluate("d2:count(#{v1})", values))

val values2 = mapOf("v1" to RuleVariableValue(ValueType.NUMBER).copy(candidates = listOf("1", "2")))
assertEquals(2, evaluate("d2:count(#{v1})", values2))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import kotlin.test.assertEquals
*
* @author Jan Bernitt
*/
internal class AvgTest : AbstractAggregateFunctionTest() {
internal class VectorAvgTest : AbstractVectorBasedTest() {

@Test
fun testAvg_Single() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.hisp.dhis.lib.expression.function

import kotlin.test.Test
import kotlin.test.assertEquals

/**
* Tests the `count` function
*
* @author Jan Bernitt
*/
internal class VectorCountTest : AbstractVectorBasedTest() {

@Test
fun testCount() {
val dataValues = mapOf(
newDeDataItem("u1234567890") to doubleArrayOf(0.0, 20.0, 5.0, 3.0, 7.0))
assertEquals(5.0, evaluate("count(#{u1234567890})", dataValues))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import kotlin.test.assertEquals
*
* @author Jan Bernitt
*/
internal class MaxTest : AbstractAggregateFunctionTest() {
internal class VectorMaxTest : AbstractVectorBasedTest() {

@Test
fun testMax() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import kotlin.test.assertNull
*
* @author Jan Bernitt
*/
internal class MedianTest : AbstractAggregateFunctionTest() {
internal class VectorMedianTest : AbstractVectorBasedTest() {

@Test
fun testMedian_Empty() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import kotlin.test.assertEquals
*
* @author Jan Bernitt
*/
internal class MinTest : AbstractAggregateFunctionTest() {
internal class VectorMinTest : AbstractVectorBasedTest() {

@Test
fun testMin() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.hisp.dhis.lib.expression.function

import kotlin.test.Test
import kotlin.test.assertEquals

/**
* Tests the `percentileCont` function
*
* @author Jan Bernitt
*/
internal class VectorPercentileContTest : AbstractVectorBasedTest() {

/*
OBS! The tests only confirm the current behaviour is stable.
Whether it is correct or not is unclear as there were no tests
*/

@Test
fun testPercentileCont() {
val dataValues = mapOf(
newDeDataItem("u1234567890") to doubleArrayOf(0.0, 20.0, 5.0, 3.0, 7.0))
// 0.5 is median
assertEquals(5.0, evaluate("percentileCont(#{u1234567890}, 0.5)", dataValues))
// this should give something else
assertEquals(3.0, evaluate("percentileCont(#{u1234567890}, 0.25)", dataValues))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.hisp.dhis.lib.expression.function

import kotlin.test.Test
import kotlin.test.assertEquals

/**
* Tests the `stddevPop` function
*
* @author Jan Bernitt
*/
internal class VectorStddevPopTest : AbstractVectorBasedTest() {

@Test
fun testStddevPop() {
val dataValues = mapOf(
newDeDataItem("u1234567890") to doubleArrayOf(2.0, 3.0, 3.0, 8.0, 10.0, 10.0))
assertEquals(3.415650255319866, evaluate("stddevPop(#{u1234567890})", dataValues))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.hisp.dhis.lib.expression.function

import kotlin.test.Test
import kotlin.test.assertEquals

/**
* Tests the `stddev` and `stddevSamp` function (same function, alias names)
*
* @author Jan Bernitt
*/
internal class VectorStddevSampTest : AbstractVectorBasedTest() {

@Test
fun testStddev() {
val dataValues = mapOf(
newDeDataItem("u1234567890") to doubleArrayOf(2.0, 3.0, 3.0, 8.0, 10.0, 10.0))
assertEquals(3.7416573867739413, evaluate("stddev(#{u1234567890})", dataValues))
}

@Test
fun testStddevSamp() {
val dataValues = mapOf(
newDeDataItem("u1234567890") to doubleArrayOf(2.0, 3.0, 3.0, 8.0, 10.0, 10.0))
assertEquals(3.7416573867739413, evaluate("stddevSamp(#{u1234567890})", dataValues))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import kotlin.test.assertEquals
*
* @author Jan Bernitt
*/
internal class SumTest : AbstractAggregateFunctionTest() {
internal class VectorSumTest : AbstractVectorBasedTest() {

@Test
fun testSum() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.hisp.dhis.lib.expression.function

import kotlin.test.Test
import kotlin.test.assertEquals

/**
* Tests the `variance` function
*
* @author Jan Bernitt
*/
internal class VectorVarianceTest : AbstractVectorBasedTest() {

@Test
fun testVariance() {
val dataValues = mapOf(
newDeDataItem("u1234567890") to doubleArrayOf(6.0, 7.0, 8.0, 9.0, 10.0))
assertEquals(2.5, evaluate("variance(#{u1234567890})", dataValues))

val dataValues2 = mapOf(
newDeDataItem("u1234567890") to doubleArrayOf(4.0, 6.0, 8.0, 10.0, 12.0))
assertEquals(10.0, evaluate("variance(#{u1234567890})", dataValues2))
}
}