Note

This page renders committed notebook outputs. The Read the Docs build does not execute notebook code.

Closure algebra diagnostics and formula metadata#

Current surface: V0.29.

Purpose#

Build intuition for algebraic diagnostics while keeping them separate from PDE residual invariance and empirical finite-transform validation.

What you will learn#

  • What closure, antisymmetry, Jacobi, and span summaries measure for small polynomial families.

  • How FormulaGeneratorFamily stores safe metadata rather than executable code.

  • Why algebraic evidence and residual-preservation evidence answer different questions.

Required extras#

Core install is enough.

Expected runtime#

Under 1 minute.

Out of scope#

No neural generators, no arbitrary strings, no finite-flow integration from formulas, no proof that closure implies PDE symmetry.

These notebooks are tutorials, not API contracts. Example outputs are runtime summaries, not canonical paper artifacts.

[1]:
from pathlib import Path
import sys

ROOT = Path.cwd()
if not (ROOT / "pyproject.toml").exists():
    ROOT = ROOT.parent
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))
import numpy as np

from notebooks._tutorial_utils import pretty_json
from pdelie import GeneratorFamily
from pdelie.data import generate_heat_1d_field_batch
from pdelie.reporting import summarize_formula_generator_family
from pdelie.residuals import HeatResidualEvaluator
from pdelie.symmetry import FormulaGeneratorFamily, compare_generator_spans, diagnose_generator_family_closure, validate_symmetry_candidate

CONFIG = {"field_seed": 650}
CONFIG

[1]:
{'field_seed': 650}

1. A small polynomial family has algebra diagnostics#

The two rows below represent translation and scaling on a one-dimensional coordinate basis. Closure diagnostics inspect the vector-field algebra; they are not a finite-transform verification report.

[2]:
basis_spec = {
    "variables": ["x"],
    "component_names": ["xi"],
    "basis_terms": [{"label": "1", "powers": [0]}, {"label": "x", "powers": [1]}],
    "component_ordering": ["xi"],
    "term_ordering": ["1", "x"],
    "layout": "component_major",
}
family = GeneratorFamily(
    parameterization="algebraic_fixture",
    coefficients=np.asarray([[1.0, 0.0], [0.0, 1.0]], dtype=float),
    basis_spec=basis_spec,
    normalization="tutorial_fixture",
    generator_names=["translation", "scaling"],
    diagnostics={},
)
closure = diagnose_generator_family_closure(family)
print(pretty_json({
    "family_rank": closure["family_rank"],
    "closure_summary": closure["closure"]["summary"],
    "antisymmetry_summary": closure["antisymmetry"]["summary"],
    "jacobi_summary": closure["jacobi"]["summary"],
}))

{
  "antisymmetry_summary": 0.0,
  "closure_summary": 0.0,
  "family_rank": 2,
  "jacobi_summary": 0.0
}

2. Span comparison asks a different algebraic question#

Closure checks whether a family is algebraically stable under brackets. Span comparison asks whether two families represent the same row span under the frozen polynomial inner product.

[3]:
span = compare_generator_spans(family, family)
print(pretty_json({
    "principal_angles_radians": span["principal_angles_radians"],
    "projection_residual_summary": span["projection_residual"]["summary"],
    "conditioning": span["conditioning"],
}, max_chars=2500))
{
  "conditioning": {
    "ambient_metric": 3.0,
    "candidate_span": 1.7320508075688774,
    "reference_span": 1.7320508075688774
  },
  "principal_angles_radians": [
    0.0,
    0.0
  ],
  "projection_residual_summary": 0.0
}

3. Formula-backed records are metadata plus safe diagnostics#

FormulaGeneratorFamily does not parse Python strings or accept callables. It stores a small JSON AST for scalar 1D Lie-point generator components.

[4]:
formula = FormulaGeneratorFamily(
    formula_generators=[
        {
            "name": "trigonometric_formula",
            "components": {
                "tau": {"node": "const", "value": 0.0},
                "xi": {"node": "sin", "arg": {"node": "var", "name": "x"}},
                "phi": {"node": "cos", "arg": {"node": "var", "name": "u"}},
            },
        },
        {
            "name": "symbolic_reference_only",
            "components": {
                "tau": {"node": "const", "value": 0.0},
                "xi": {"node": "symbolic_reference", "label": "external_xi", "metadata": {"system": "tutorial"}},
                "phi": {"node": "const", "value": 0.0},
            },
        },
    ],
)
formula_summary = summarize_formula_generator_family(formula)
print(pretty_json(formula_summary, max_chars=3500))

{
  "component_names": [
    "tau",
    "xi",
    "phi"
  ],
  "component_nodes": {
    "phi": [
      "cos",
      "const"
    ],
    "tau": [
      "const",
      "const"
    ],
    "xi": [
      "sin",
      "symbolic_reference"
    ]
  },
  "diagnostics": {},
  "finite_transform_available": false,
  "finite_transform_construction_method": null,
  "formula_kinds": {
    "const": 3,
    "cos": 1,
    "sin": 1,
    "symbolic_reference": 1,
    "var": 2
  },
  "generator_count": 2,
  "generator_names": [
    "trigonometric_formula",
    "symbolic_reference_only"
  ],
  "parameterization": "formula_generator_family",
  "reciprocal_denominator_floor": 1e-12,
  "schema_version": "0.1",
  "summary_schema_version": "0.1",
  "summary_type": "formula_generator_family",
  "symbolic_references": [
    {
      "component": "xi",
      "generator_name": "symbolic_reference_only",
      "label": "external_xi",
      "metadata": {
        "system": "tutorial"
      }
    }
  ],
  "variables": [
    "t",
    "x",
    "u"
  ]
}

4. Empirical configured validation is not a proof#

A formula can be schema-valid and finite on a field without proving it is a symmetry. Without a supported finite transform, the conclusion can be partial.

[5]:
field = generate_heat_1d_field_batch(batch_size=3, num_times=9, num_points=32, seed=CONFIG["field_seed"])
report = validate_symmetry_candidate(field, formula, residual_evaluator=HeatResidualEvaluator())
print(pretty_json({
    "candidate_kind": report["candidate_kind"],
    "conclusion": report["conclusion"],
    "configured_checks": report["configured_validation_checks"],
}, max_chars=3500))

{
  "candidate_kind": "formula_generator_family",
  "conclusion": "partially_validated",
  "configured_checks": [
    "schema",
    "formula_evaluation_diagnostics",
    "finite_transform_spec_validation"
  ]
}

Recap#

Closure, span comparison, formula metadata, and finite-transform validation are related but distinct evidence channels.

Common pitfalls#

  • Assuming closure diagnostics prove PDE residual invariance.

  • Treating formula metadata as executable code.

  • Treating symbolic-reference formulas as evaluated formulas.

  • Forgetting that empirical configured validation is not proof.

Extension ideas#

  • Add a second polynomial family and compare spans.

  • Attach a supported finite-transform spec to a formula-backed translation candidate.

  • Use formula records to document external symbolic candidates before validation.

What to read/run next#

Run 07_external_symmetry_candidates.ipynb for the full candidate-validation dashboard.