Skip to content

Commit

Permalink
feat: added basic validation logic to HierarchyValidator.kt
Browse files Browse the repository at this point in the history
- checking edge sums for all nodes
- calling isValid method for all node strategies
  • Loading branch information
janniclas committed Aug 26, 2024
1 parent f1a013f commit b224966
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,30 @@

package de.fraunhofer.iem.kpiCalculator.core.hierarchy

import de.fraunhofer.iem.kpiCalculator.core.strategy.AggregationKPICalculationStrategy
import de.fraunhofer.iem.kpiCalculator.core.strategy.MaximumKPICalculationStrategy
import de.fraunhofer.iem.kpiCalculator.core.strategy.RatioKPICalculationStrategy
import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiStrategyId
import de.fraunhofer.iem.kpiCalculator.model.kpi.hierarchy.KpiHierarchy
import de.fraunhofer.iem.kpiCalculator.model.kpi.hierarchy.KpiNode
import io.github.oshai.kotlinlogging.KotlinLogging

private val logger = KotlinLogging.logger {}

object HierarchyValidator {
//TODO: return type will most likely be changed to a complex type comparably to KpiCalculationResult

/**
* Validates the semantic structure of the given KpiHierarchy.
*
* Checks edge weight sums (must always be 1.0).
*
* Uses KpiCalculationStrategy isValid method on each node.
*
* @param kpiHierarchy hierarchy to validate.
* @param strict validation mode. Some errors in strict may only be warnings in relaxed mode.
*
* @return if the hierarchy is valid.
*/
fun isValid(kpiHierarchy: KpiHierarchy, strict: Boolean = false): Boolean {
// TODO: check the schema version and build a schema specific validation if necessary
logger.info { "Started KPI hierarchy validation with strict mode $strict." }
Expand All @@ -30,6 +47,49 @@ object HierarchyValidator {
}
}


return validateStrategies(root, strict)
}

private fun validateStrategies(node: KpiNode, strict: Boolean): Boolean {

if (node.edges.isNotEmpty()) {
val edgeWeightSum = node.edges.sumOf { it.weight }
if (edgeWeightSum != 1.0) {
logger.error {
"Incorrect edge weights. Should sum up to 1.0 " +
"actual sum of weights $edgeWeightSum."
}
return false
}
}

val isValid = when (node.kpiStrategyId) {
KpiStrategyId.RAW_VALUE_STRATEGY -> {
if (node.edges.isNotEmpty()) {
logger.error { "Raw Value nodes must not have children as they expect only tool results." }
false
} else {
true
}
}

KpiStrategyId.AGGREGATION_STRATEGY -> AggregationKPICalculationStrategy.isValid(node, strict)
KpiStrategyId.MAXIMUM_STRATEGY -> MaximumKPICalculationStrategy.isValid(node, strict)
KpiStrategyId.RATIO_STRATEGY -> RatioKPICalculationStrategy.isValid(node, strict)
}

if (!isValid) {
return false
}

node.edges.forEach { edge ->
val isValidEdge = validateStrategies(edge.target, strict)
if (!isValidEdge) {
return@validateStrategies false
}
}

return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ internal object MaximumKPICalculationStrategy : BaseKpiCalculationStrategy() {

if (node.edges.size == 1) {
logger.warn {
"Maximum KPI calculation strategy for node $node is planned" +
"Maximum KPI calculation strategy for node $node is planned " +
"for a single child."
}
}
Expand Down

0 comments on commit b224966

Please sign in to comment.