@@ -23,15 +23,15 @@ import com.google.privacy.differentialprivacy.pipelinedp4j.core.DpEngine
2323import com.google.privacy.differentialprivacy.pipelinedp4j.core.DpEngineBudgetSpec
2424import com.google.privacy.differentialprivacy.pipelinedp4j.core.Encoder
2525import com.google.privacy.differentialprivacy.pipelinedp4j.core.EncoderFactory
26+ import com.google.privacy.differentialprivacy.pipelinedp4j.core.FeatureSpec
2627import com.google.privacy.differentialprivacy.pipelinedp4j.core.FeatureValuesExtractor
2728import com.google.privacy.differentialprivacy.pipelinedp4j.core.FrameworkCollection
2829import com.google.privacy.differentialprivacy.pipelinedp4j.core.FrameworkTable
2930import com.google.privacy.differentialprivacy.pipelinedp4j.core.MetricType
31+ import com.google.privacy.differentialprivacy.pipelinedp4j.core.ScalarFeatureSpec
3032import com.google.privacy.differentialprivacy.pipelinedp4j.core.SelectPartitionsParams
3133import com.google.privacy.differentialprivacy.pipelinedp4j.proto.DpAggregates
32- import com.google.privacy.differentialprivacy.pipelinedp4j.proto.PerFeature
3334import com.google.privacy.differentialprivacy.pipelinedp4j.proto.copy
34- import com.google.privacy.differentialprivacy.pipelinedp4j.proto.dpAggregates
3535import com.google.privacy.differentialprivacy.pipelinedp4j.proto.perFeature
3636
3737sealed interface Query <ReturnT > {
@@ -142,21 +142,6 @@ protected constructor(
142142 valueAndVectorAggs.map { it.getFeatureId() }
143143 }
144144 return aggResults
145- .zip(featureIdPerRun)
146- .map { (table, featureId) ->
147- table.mapValues(" TagWithFeatureId" , encoderFactory.protos(DpAggregates ::class )) { _, agg ->
148- if (featureId == null ) {
149- agg
150- } else {
151- val perFeature = constructPerFeature(agg, featureId)
152- dpAggregates {
153- count = agg.count
154- privacyIdCount = agg.privacyIdCount
155- this .perFeature + = perFeature
156- }
157- }
158- }
159- }
160145 .reduce {
161146 acc: FrameworkTable <GroupKeysT , DpAggregates >,
162147 table: FrameworkTable <GroupKeysT , DpAggregates > ->
@@ -496,41 +481,59 @@ protected constructor(
496481 ): AggregationParams {
497482 val valueContributionBounds = valueAggregations?.contributionBounds
498483 val vectorContributionBounds = vectorAggregations?.vectorContributionBounds
484+
485+ val topLevelMetrics =
486+ aggregationSpecs
487+ .filter { it is Count || it is PrivacyIdCount }
488+ .map { it.toMetricDefinition() }
489+ val features =
490+ mutableListOf< com.google.privacy.differentialprivacy.pipelinedp4j.core.FeatureSpec > ()
491+ if (valueAggregations != null ) {
492+ features.add(
493+ com.google.privacy.differentialprivacy.pipelinedp4j.core.ScalarFeatureSpec (
494+ featureId = valueAggregations.getFeatureId(),
495+ metrics =
496+ ImmutableList .copyOf(
497+ valueAggregations.valueAggregationSpecs.map { it.toMetricDefinition() }
498+ ),
499+ minValue = valueContributionBounds?.valueBounds?.minValue,
500+ maxValue = valueContributionBounds?.valueBounds?.maxValue,
501+ minTotalValue = valueContributionBounds?.totalValueBounds?.minValue,
502+ maxTotalValue = valueContributionBounds?.totalValueBounds?.maxValue,
503+ )
504+ )
505+ }
506+ if (vectorAggregations != null ) {
507+ checkNotNull(vectorContributionBounds)
508+ features.add(
509+ com.google.privacy.differentialprivacy.pipelinedp4j.core.VectorFeatureSpec (
510+ featureId = vectorAggregations.getFeatureId(),
511+ metrics =
512+ ImmutableList .copyOf(
513+ vectorAggregations.vectorAggregationSpecs.map { it.toMetricDefinition() }
514+ ),
515+ vectorSize =
516+ checkNotNull(vectorAggregations.vectorSize) {
517+ " vectorSize must be set for vector aggregations"
518+ },
519+ normKind = vectorContributionBounds.maxVectorTotalNorm.normKind.toInternalNormKind(),
520+ vectorMaxTotalNorm = vectorContributionBounds.maxVectorTotalNorm.value,
521+ )
522+ )
523+ }
524+
499525 return AggregationParams (
500- metrics = ImmutableList .copyOf(aggregationSpecs.metrics()),
526+ metrics = ImmutableList .copyOf(topLevelMetrics),
527+ features = ImmutableList .copyOf(features),
501528 noiseKind =
502529 checkNotNull(noiseKind) { " noiseKind cannot be null if there are aggregations." }
503530 .toInternalNoiseKind(),
504531 maxPartitionsContributed = contributionBoundingLevel.getMaxPartitionsContributed(),
505532 maxContributionsPerPartition = contributionBoundingLevel.getMaxContributionsPerPartition(),
506- minValue = valueContributionBounds?.valueBounds?.minValue,
507- maxValue = valueContributionBounds?.valueBounds?.maxValue,
508- minTotalValue = valueContributionBounds?.totalValueBounds?.minValue,
509- maxTotalValue = valueContributionBounds?.totalValueBounds?.maxValue,
510- vectorNormKind = vectorContributionBounds?.maxVectorTotalNorm?.normKind?.toInternalNormKind(),
511- vectorMaxTotalNorm = vectorContributionBounds?.maxVectorTotalNorm?.value,
512- vectorSize = vectorAggregations?.vectorSize,
513533 partitionSelectionBudget = groupsType.getBudget()?.toInternalBudgetPerOpSpec(),
514534 preThreshold = groupsType.getPreThreshold(),
515535 contributionBoundingLevel = contributionBoundingLevel.toInternalContributionBoundingLevel(),
516536 partitionsBalance = groupByAdditionalParameters.groupsBalance.toPartitionsBalance(),
517537 )
518538 }
519-
520- companion object {
521- private fun constructPerFeature (dpAggregates : DpAggregates , featureId : String ): PerFeature {
522- return perFeature {
523- this .featureId = featureId
524- sum = dpAggregates.sum
525- mean = dpAggregates.mean
526- variance = dpAggregates.variance
527- if (dpAggregates.quantilesList.isNotEmpty()) {
528- quantiles + = dpAggregates.quantilesList
529- }
530- if (dpAggregates.vectorSumList.isNotEmpty()) {
531- vectorSum + = dpAggregates.vectorSumList
532- }
533- }
534- }
535- }
536539}
0 commit comments