Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
8e128f8
wip single table
sarahmish Aug 19, 2026
ad40bb1
add denormalized table
sarahmish Aug 20, 2026
0a18f3a
test denormalized table
sarahmish Aug 20, 2026
18dcbac
add unit tests
sarahmish Aug 20, 2026
468966d
fix lint
sarahmish Aug 20, 2026
0eccd59
constraint adherence
sarahmish Aug 21, 2026
1ee4b58
add error file
sarahmish Aug 21, 2026
58154d3
add one hot encoding
sarahmish Aug 21, 2026
b40ced1
add range constraint
sarahmish Aug 21, 2026
1fee50e
add inequality
sarahmish Aug 21, 2026
ab4bec8
add chained inequality
sarahmish Aug 21, 2026
7bf255b
add fixed increments
sarahmish Aug 21, 2026
ad42094
add fixed combinations
sarahmish Aug 21, 2026
8f78e0a
add fixed combinations
sarahmish Aug 23, 2026
32bde74
add fixed null combinations
sarahmish Aug 23, 2026
134e363
add column formula
sarahmish Aug 23, 2026
18d790b
add carryover column
sarahmish Aug 25, 2026
cac3452
mixed scales
sarahmish Aug 25, 2026
8139182
fix
sarahmish Aug 25, 2026
380561c
docstrings
sarahmish Aug 26, 2026
c4c41c8
add self referential hierarchy
sarahmish Aug 26, 2026
6be5fc5
remove multi-table constraints
sarahmish Aug 26, 2026
d94d35d
clean up
sarahmish Aug 26, 2026
95d7dda
clean tests
sarahmish Aug 26, 2026
42a2461
fix tests
sarahmish Aug 27, 2026
244f120
add utils tests
sarahmish Aug 31, 2026
c1f7e16
Run & Assert -> Run and Assert
sarahmish Aug 31, 2026
9cb4d21
Merge branch 'main' into issue-899-constraint-adherence
sarahmish Aug 31, 2026
f59d9af
add integration test
sarahmish Aug 31, 2026
7c6512f
Merge branch 'main' into issue-899-constraint-adherence
sarahmish Sep 1, 2026
5118a80
update warnings to logger
sarahmish Sep 10, 2026
dbb1356
add multi table consrtaint
sarahmish Aug 26, 2026
c3695cf
add foreign to foreign key
sarahmish Aug 26, 2026
262ce8e
add foreign to primary key subset
sarahmish Aug 26, 2026
3387be4
add polymorphic relationship
sarahmish Aug 27, 2026
6dcd867
add pk to pk subset
sarahmish Aug 27, 2026
d758967
add reference table test
sarahmish Aug 27, 2026
dbe67be
fix imports
sarahmish Aug 27, 2026
eacdbcd
change Run & Assert to Run and Assert
sarahmish Aug 31, 2026
ae77ce7
add integration tests
sarahmish Aug 31, 2026
bf07376
only return relevant valid tables
sarahmish Aug 31, 2026
236897d
add utils tests
sarahmish Aug 31, 2026
59e1d0c
fix test
sarahmish Aug 31, 2026
5f84660
remove unused function
sarahmish Sep 9, 2026
09a716d
add test to check denormalized primary key
sarahmish Sep 10, 2026
61b98a8
add more test coverage
sarahmish Sep 12, 2026
433d07b
update reference table
sarahmish Sep 14, 2026
5b200a2
reuse foreign key
sarahmish Sep 14, 2026
8ded575
Merge branch 'main' into issue-899-constraint-adherence
sarahmish Sep 15, 2026
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
2 changes: 2 additions & 0 deletions sdmetrics/multi_table/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from sdmetrics.multi_table.statistical.cardinality_statistic_similarity import (
CardinalityStatisticSimilarity,
)
from sdmetrics.multi_table.statistical.constraint_adherence import ConstraintAdherence

__all__ = [
'detection',
Expand Down Expand Up @@ -59,4 +60,5 @@
'TVComplement',
'RangeCoverage',
'NewRowSynthesis',
'ConstraintAdherence',
]
3 changes: 2 additions & 1 deletion sdmetrics/multi_table/statistical/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
from sdmetrics.multi_table.statistical.cardinality_statistic_similarity import (
CardinalityStatisticSimilarity,
)
from sdmetrics.multi_table.statistical.constraint_adherence import ConstraintAdherence

__all__ = ['CardinalityShapeSimilarity', 'CardinalityStatisticSimilarity']
__all__ = ['CardinalityShapeSimilarity', 'CardinalityStatisticSimilarity', 'ConstraintAdherence']
79 changes: 79 additions & 0 deletions sdmetrics/multi_table/statistical/constraint_adherence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""Constraint Adherence metric."""

import logging
import warnings

import numpy as np
import pandas as pd

from sdmetrics.goal import Goal
from sdmetrics.multi_table.base import MultiTableMetric
from sdmetrics.multi_table.statistical.constraints.base import BaseConstraint
from sdmetrics.multi_table.statistical.constraints.error import ConstraintNotApplicableError

LOGGER = logging.getLogger(__name__)


class ConstraintAdherence(MultiTableMetric):
"""Constraint Adherence metric.

Compute the fraction of data points in the synthetic data that
follow the specified constraint.

Attributes:
name (str):
Name to use when reports about this metric are printed.
goal (sdmetrics.goal.Goal):
The goal of this metric.
min_value (float):
Minimum value that this metric can take.
max_value (float):
Maximum value that this metric can take.
"""

name = 'ConstraintAdherence'
goal = Goal.MAXIMIZE
min_value = 0.0
max_value = 1.0

@classmethod
def compute(cls, real_data, synthetic_data, metadata, constraint):
"""Compute the percentage of rows that adhere to the constraint.

Args:
real_data (dict[str, pandas.DataFrame]):
The tables from the real dataset, passed as a dictionary of
table names and pandas.DataFrames.
synthetic_data (dict[str, pandas.DataFrame]):
The tables from the synthetic dataset, passed as a dictionary of
table names and pandas.DataFrames.
metadata (dict):
Multi-table metadata dict.
constraint (dict):
A dictionary that defines the type of constraint and its parameters.

Returns:
float:
The proportion of data points in the synthetic data that match
the specified constraint format.
"""
constraint = BaseConstraint.load_constraint_from_dict(constraint)

try:
constraint.fit(real_data, metadata)
real_score = constraint.get_score(real_data, metadata)
except ConstraintNotApplicableError as error:
LOGGER.warning(f'Unable to check the constraint against the real data: {error}')
real_score = np.nan

if not pd.isna(real_score) and real_score < 1.0:
warnings.warn(
f"The real data does not adhere to the '{constraint.__class__.__name__}' "
f'constraint ({round(real_score * 100, 2)}% of the rows are valid). '
)

try:
return constraint.get_score(synthetic_data, metadata)
except ConstraintNotApplicableError as error:
LOGGER.warning(f'Unable to check the constraint against the synthetic data: {error}')
return np.nan
55 changes: 55 additions & 0 deletions sdmetrics/multi_table/statistical/constraints/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Constraints."""

from sdmetrics.multi_table.statistical.constraints.base import BaseConstraint
from sdmetrics.multi_table.statistical.constraints.carry_over_columns import CarryOverColumns
from sdmetrics.multi_table.statistical.constraints.column_formula import ColumnFormula
from sdmetrics.multi_table.statistical.constraints.denormalized_table import (
DenormalizedTable,
)
from sdmetrics.multi_table.statistical.constraints.chained_inequality import ChainedInequality
from sdmetrics.multi_table.statistical.constraints.inequality import Inequality
from sdmetrics.multi_table.statistical.constraints.fixed_combinations import FixedCombinations
from sdmetrics.multi_table.statistical.constraints.fixed_increments import FixedIncrements
from sdmetrics.multi_table.statistical.constraints.fixed_null_combinations import (
FixedNullCombinations,
)
from sdmetrics.multi_table.statistical.constraints.foreign_to_foreign_key import (
ForeignToForeignKey,
)
from sdmetrics.multi_table.statistical.constraints.foreign_to_primary_key_subset import (
ForeignToPrimaryKeySubset,
)
from sdmetrics.multi_table.statistical.constraints.mixed_scales import MixedScales
from sdmetrics.multi_table.statistical.constraints.polymorphic_relationship import (
PolymorphicRelationship,
)
from sdmetrics.multi_table.statistical.constraints.primary_to_primary_key_subset import (
PrimaryToPrimaryKeySubset,
)
from sdmetrics.multi_table.statistical.constraints.reference_table import ReferenceTable
from sdmetrics.multi_table.statistical.constraints.one_hot_encoding import OneHotEncoding
from sdmetrics.multi_table.statistical.constraints.range import Range
from sdmetrics.multi_table.statistical.constraints.referential_hierarchy import (
SelfReferentialHierarchy,
)

__all__ = (
BaseConstraint,
CarryOverColumns,
ColumnFormula,
DenormalizedTable,
ChainedInequality,
Inequality,
FixedIncrements,
FixedCombinations,
FixedNullCombinations,
ForeignToForeignKey,
ForeignToPrimaryKeySubset,
MixedScales,
PolymorphicRelationship,
PrimaryToPrimaryKeySubset,
ReferenceTable,
OneHotEncoding,
Range,
SelfReferentialHierarchy,
)
Loading