-
Notifications
You must be signed in to change notification settings - Fork 188
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Clean-up and improve simulations schema
All values of a given metric (different partitions at various levels of detail) are now kept in a single SimulationMetricValuesType instance. Other changes: - Both definition and run-time schema structure and item/type names were improved. - On-demand value aggregation was implemented, to support GUI in dynamic displaying of the values. See SimulationMetricValuesTypeUtil and SimulationMetricComputer. Work in progress.
- Loading branch information
Showing
25 changed files
with
943 additions
and
522 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
90 changes: 90 additions & 0 deletions
90
infra/schema/src/main/java/com/evolveum/midpoint/schema/simulation/PartitionScope.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* Copyright (C) 2010-2023 Evolveum and contributors | ||
* | ||
* This work is dual-licensed under the Apache License 2.0 | ||
* and European Union Public License. See LICENSE file for details. | ||
*/ | ||
|
||
package com.evolveum.midpoint.schema.simulation; | ||
|
||
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; | ||
import com.evolveum.midpoint.xml.ns._public.common.common_3.SimulationMetricPartitionScopeType; | ||
|
||
import javax.xml.namespace.QName; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
/** | ||
* Parsed form of {@link SimulationMetricPartitionScopeType}. | ||
* | ||
* TODO reconcile these two; what to do with null dimensions? | ||
*/ | ||
public class PartitionScope { | ||
|
||
private final QName objectType; | ||
private final String resourceOid; | ||
private final ShadowKindType kind; | ||
private final String intent; | ||
|
||
public PartitionScope(QName objectType, String resourceOid, ShadowKindType kind, String intent) { | ||
this.objectType = objectType; | ||
this.resourceOid = resourceOid; | ||
this.kind = kind; | ||
this.intent = intent; | ||
} | ||
|
||
public static PartitionScope fromBean(SimulationMetricPartitionScopeType scope) { | ||
if (scope == null) { | ||
return new PartitionScope(null, null, null, null); | ||
} else { | ||
return new PartitionScope( | ||
scope.getTypeName(), | ||
scope.getResourceOid(), | ||
scope.getKind(), | ||
scope.getIntent()); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
PartitionScope that = (PartitionScope) o; | ||
return Objects.equals(objectType, that.objectType) | ||
&& Objects.equals(resourceOid, that.resourceOid) | ||
&& kind == that.kind | ||
&& Objects.equals(intent, that.intent); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(objectType, resourceOid, kind, intent); | ||
} | ||
|
||
public SimulationMetricPartitionScopeType toBean() { | ||
// FIXME fill nullDimensions correctly | ||
SimulationMetricPartitionScopeType bean = new SimulationMetricPartitionScopeType() | ||
.typeName(objectType) | ||
.resourceOid(resourceOid) | ||
.kind(kind) | ||
.intent(intent); | ||
List<QName> nullDimensions = bean.getNullDimensions(); | ||
if (objectType == null) { | ||
nullDimensions.add(SimulationMetricPartitionScopeType.F_TYPE_NAME); | ||
} | ||
if (resourceOid == null) { | ||
nullDimensions.add(SimulationMetricPartitionScopeType.F_RESOURCE_OID); | ||
} | ||
if (kind == null) { | ||
nullDimensions.add(SimulationMetricPartitionScopeType.F_KIND); | ||
} | ||
if (intent == null) { | ||
nullDimensions.add(SimulationMetricPartitionScopeType.F_INTENT); | ||
} | ||
return bean; | ||
} | ||
} |
123 changes: 123 additions & 0 deletions
123
...chema/src/main/java/com/evolveum/midpoint/schema/simulation/SimulationMetricComputer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* | ||
* Copyright (C) 2010-2023 Evolveum and contributors | ||
* | ||
* This work is dual-licensed under the Apache License 2.0 | ||
* and European Union Public License. See LICENSE file for details. | ||
*/ | ||
|
||
package com.evolveum.midpoint.schema.simulation; | ||
|
||
import static com.evolveum.midpoint.schema.util.SimulationMetricValuesTypeUtil.selectPartitions; | ||
|
||
import java.math.BigDecimal; | ||
import java.math.RoundingMode; | ||
import java.util.List; | ||
import java.util.Set; | ||
import javax.xml.namespace.QName; | ||
|
||
import com.evolveum.midpoint.schema.util.SimulationMetricPartitionDimensionsTypeUtil; | ||
import com.evolveum.midpoint.xml.ns._public.common.common_3.SimulationMetricValuesType; | ||
|
||
import com.google.common.collect.Sets; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import com.evolveum.midpoint.xml.ns._public.common.common_3.SimulationMetricAggregationFunctionType; | ||
import com.evolveum.midpoint.xml.ns._public.common.common_3.SimulationMetricPartitionType; | ||
|
||
/** | ||
* Works with the metric computations at one place. | ||
* | ||
* (Called from various x-Type-Util classes.) | ||
*/ | ||
public class SimulationMetricComputer { | ||
|
||
private static final int DEFAULT_SCALE = 10; | ||
|
||
public static List<SimulationMetricPartitionType> computePartitions( | ||
@NotNull SimulationMetricValuesType mv, @NotNull Set<QName> dimensions) { | ||
Set<QName> sourceDimensions = SimulationMetricPartitionDimensionsTypeUtil.getDimensions(mv.getSourceDimensions()); | ||
Set<QName> missing = Sets.difference(dimensions, sourceDimensions); | ||
if (!missing.isEmpty()) { | ||
throw new IllegalArgumentException( | ||
String.format( | ||
"Cannot compute partition for %s as the following dimension(s) are missing: %s; source = %s", | ||
dimensions, missing, sourceDimensions)); | ||
} | ||
SimulationMetricPartitions targetPartitions = new SimulationMetricPartitions(); | ||
for (SimulationMetricPartitionType sourcePartitionBean : selectPartitions(mv, sourceDimensions)) { | ||
targetPartitions.addPartition(sourcePartitionBean); | ||
} | ||
return targetPartitions.toPartitionBeans(mv.getAggregationFunction()); | ||
} | ||
|
||
@SuppressWarnings("SameParameterValue") | ||
static BigDecimal computeValue( | ||
SimulationMetricPartitionType partition, | ||
SimulationMetricAggregationFunctionType function, | ||
ComputationParameters computationParameters) { | ||
switch (function) { | ||
case SELECTION_SIZE: | ||
return asBigDecimal(partition.getSelectionSize()); | ||
case SELECTION_TOTAL_VALUE: | ||
return partition.getSelectionTotalValue(); | ||
case DOMAIN_SIZE: | ||
return asBigDecimal(partition.getDomainSize()); | ||
case DOMAIN_TOTAL_VALUE: | ||
return partition.getDomainTotalValue(); | ||
case SELECTION_SIZE_TO_DOMAIN_SIZE: | ||
return ratio( | ||
asBigDecimal(partition.getSelectionSize()), | ||
asBigDecimal(partition.getDomainSize()), | ||
computationParameters); | ||
case SELECTION_TOTAL_VALUE_TO_DOMAIN_SIZE: | ||
return ratio( | ||
partition.getSelectionTotalValue(), | ||
asBigDecimal(partition.getDomainSize()), | ||
computationParameters); | ||
case DOMAIN_TOTAL_VALUE_TO_DOMAIN_SIZE: | ||
return ratio( | ||
partition.getDomainTotalValue(), | ||
asBigDecimal(partition.getDomainSize()), | ||
computationParameters); | ||
case SELECTION_TOTAL_VALUE_TO_DOMAIN_TOTAL_VALUE: | ||
return ratio( | ||
partition.getSelectionTotalValue(), | ||
partition.getDomainTotalValue(), | ||
computationParameters); | ||
case SELECTION_MIN_VALUE: | ||
return partition.getSelectionMinValue(); | ||
case DOMAIN_MIN_VALUE: | ||
return partition.getDomainMinValue(); | ||
case SELECTION_MAX_VALUE: | ||
return partition.getSelectionMaxValue(); | ||
case DOMAIN_MAX_VALUE: | ||
return partition.getDomainMaxValue(); | ||
default: | ||
throw new AssertionError(function); | ||
} | ||
} | ||
|
||
private static BigDecimal asBigDecimal(Integer value) { | ||
return value != null ? BigDecimal.valueOf(value) : null; | ||
} | ||
|
||
private static BigDecimal ratio(BigDecimal part, BigDecimal total, ComputationParameters parameters) { | ||
if (part == null || total == null || BigDecimal.ZERO.equals(total)) { | ||
return null; | ||
} else { | ||
return part.divide(total, ComputationParameters.getScale(parameters), RoundingMode.HALF_UP); | ||
} | ||
} | ||
|
||
public static class ComputationParameters { | ||
private final int scale; | ||
|
||
public ComputationParameters(int scale) { | ||
this.scale = scale; | ||
} | ||
|
||
static int getScale(ComputationParameters parameters) { | ||
return parameters != null ? parameters.scale : DEFAULT_SCALE; | ||
} | ||
} | ||
} |
100 changes: 100 additions & 0 deletions
100
...hema/src/main/java/com/evolveum/midpoint/schema/simulation/SimulationMetricPartition.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* | ||
* Copyright (C) 2010-2023 Evolveum and contributors | ||
* | ||
* This work is dual-licensed under the Apache License 2.0 | ||
* and European Union Public License. See LICENSE file for details. | ||
*/ | ||
|
||
package com.evolveum.midpoint.schema.simulation; | ||
|
||
import java.math.BigDecimal; | ||
|
||
import com.evolveum.midpoint.xml.ns._public.common.common_3.SimulationMetricAggregationFunctionType; | ||
import com.evolveum.midpoint.xml.ns._public.common.common_3.SimulationMetricPartitionType; | ||
|
||
import static com.evolveum.midpoint.util.MiscUtil.or0; | ||
|
||
/** | ||
* Parsed form of {@link SimulationMetricPartitionType}. | ||
* | ||
* Created for fast and simple aggregation. | ||
*/ | ||
public class SimulationMetricPartition { | ||
|
||
private int selectionSize; | ||
private BigDecimal selectionTotalValue = BigDecimal.ZERO; | ||
private int domainSize; | ||
private BigDecimal domainTotalValue = BigDecimal.ZERO; | ||
|
||
private BigDecimal selectionMinValue; | ||
private BigDecimal selectionMaxValue; | ||
private BigDecimal domainMinValue; | ||
private BigDecimal domainMaxValue; | ||
|
||
@SuppressWarnings("DuplicatedCode") | ||
public void addObject(BigDecimal sourceMetricValue, boolean inSelection) { | ||
if (domainMinValue == null || sourceMetricValue.compareTo(domainMinValue) < 0) { | ||
domainMinValue = sourceMetricValue; | ||
} | ||
if (domainMaxValue == null || sourceMetricValue.compareTo(domainMaxValue) > 0) { | ||
domainMaxValue = sourceMetricValue; | ||
} | ||
domainSize++; | ||
domainTotalValue = domainTotalValue.add(sourceMetricValue); | ||
|
||
if (inSelection) { | ||
if (selectionMinValue == null || sourceMetricValue.compareTo(selectionMinValue) < 0) { | ||
selectionMinValue = sourceMetricValue; | ||
} | ||
if (selectionMaxValue == null || sourceMetricValue.compareTo(selectionMaxValue) > 0) { | ||
selectionMaxValue = sourceMetricValue; | ||
} | ||
selectionSize++; | ||
selectionTotalValue = selectionTotalValue.add(sourceMetricValue); | ||
} | ||
} | ||
|
||
void addPartition(SimulationMetricPartitionType other) { | ||
BigDecimal otherDomainMinValue = other.getDomainMinValue(); | ||
if (domainMinValue == null || otherDomainMinValue != null && otherDomainMinValue.compareTo(domainMinValue) < 0) { | ||
domainMinValue = otherDomainMinValue; | ||
} | ||
BigDecimal otherDomainMaxValue = other.getDomainMaxValue(); | ||
if (domainMaxValue == null || otherDomainMaxValue != null && otherDomainMaxValue.compareTo(domainMaxValue) > 0) { | ||
domainMaxValue = otherDomainMaxValue; | ||
} | ||
domainSize += or0(other.getDomainSize()); | ||
domainTotalValue = domainTotalValue.add(or0(other.getDomainTotalValue())); | ||
|
||
BigDecimal otherSelectionMinValue = other.getSelectionMinValue(); | ||
if (selectionMinValue == null || otherSelectionMinValue != null && otherSelectionMinValue.compareTo(selectionMinValue) < 0) { | ||
selectionMinValue = otherSelectionMinValue; | ||
} | ||
BigDecimal otherSelectionMaxValue = other.getSelectionMaxValue(); | ||
if (selectionMaxValue == null || otherSelectionMaxValue != null && otherSelectionMaxValue.compareTo(selectionMaxValue) > 0) { | ||
selectionMaxValue = otherSelectionMaxValue; | ||
} | ||
selectionSize += or0(other.getSelectionSize()); | ||
selectionTotalValue = selectionTotalValue.add(or0(other.getSelectionTotalValue())); | ||
} | ||
|
||
public SimulationMetricPartitionType toBean(PartitionScope key, SimulationMetricAggregationFunctionType function) { | ||
var bean = toBean(key); | ||
bean.setValue( | ||
SimulationMetricComputer.computeValue(bean, function, null)); | ||
return bean; | ||
} | ||
|
||
private SimulationMetricPartitionType toBean(PartitionScope scope) { | ||
return new SimulationMetricPartitionType() | ||
.scope(scope.toBean()) | ||
.selectionSize(selectionSize) | ||
.selectionTotalValue(selectionTotalValue) | ||
.domainSize(domainSize) | ||
.domainTotalValue(domainTotalValue) | ||
.selectionMinValue(selectionMinValue) | ||
.selectionMaxValue(selectionMaxValue) | ||
.domainMinValue(domainMinValue) | ||
.domainMaxValue(domainMaxValue); | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
...ema/src/main/java/com/evolveum/midpoint/schema/simulation/SimulationMetricPartitions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* Copyright (C) 2010-2023 Evolveum and contributors | ||
* | ||
* This work is dual-licensed under the Apache License 2.0 | ||
* and European Union Public License. See LICENSE file for details. | ||
*/ | ||
|
||
package com.evolveum.midpoint.schema.simulation; | ||
|
||
import java.math.BigDecimal; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
|
||
import com.evolveum.midpoint.xml.ns._public.common.common_3.SimulationMetricAggregationFunctionType; | ||
import com.evolveum.midpoint.xml.ns._public.common.common_3.SimulationMetricPartitionType; | ||
|
||
public class SimulationMetricPartitions { | ||
|
||
@NotNull private final Map<PartitionScope, SimulationMetricPartition> partitions = new HashMap<>(); | ||
|
||
public List<SimulationMetricPartitionType> toPartitionBeans(@NotNull SimulationMetricAggregationFunctionType function) { | ||
return partitions.entrySet().stream() | ||
.map(e -> e.getValue().toBean(e.getKey(), function)) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
public void addObject(PartitionScope key, BigDecimal sourceMetricValue, boolean inSelection) { | ||
partitions | ||
.computeIfAbsent(key, (k) -> new SimulationMetricPartition()) | ||
.addObject(sourceMetricValue, inSelection); | ||
} | ||
|
||
void addPartition(SimulationMetricPartitionType sourcePartitionBean) { | ||
PartitionScope key = PartitionScope.fromBean(sourcePartitionBean.getScope()); | ||
partitions | ||
.computeIfAbsent(key, (k) -> new SimulationMetricPartition()) | ||
.addPartition(sourcePartitionBean); | ||
} | ||
} |
Oops, something went wrong.