Skip to content

Add symmetric option to group_structures, pass through to sm.fit() and test - #133

Merged
shyuep merged 1 commit into
materialsproject:mainfrom
kavanase:add_symmetric_option_to_group_structures
Aug 30, 2026
Merged

Add symmetric option to group_structures, pass through to sm.fit() and test#133
shyuep merged 1 commit into
materialsproject:mainfrom
kavanase:add_symmetric_option_to_group_structures

Conversation

@kavanase

@kavanase kavanase commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a small PR to add the symmetric option to StructureMatcher.group_structures(), which is then passed through to the underlying StructureMatcher.fit() usage.

Summary with the help of Claude:
StructureMatcher.fit is directional; symmetric=False by default, and its docstring says so. But group_structures consumes it as if it were an equality test: it pops a reference and always passes that reference as struct1. So which structure happens to come first decides the grouping.

This repo already keeps a structure pair for the asymmetry, used by test_fit:

# src/pymatgen/util/testing.py:36
VASP_IN_DIR: str = f"{TEST_FILES_DIR}/io/vasp/inputs"
sm = StructureMatcher(comparator=ElementComparator(), ltol=0.6, stol=0.6, angle_tol=6)
s1 = Structure.from_file(f"{VASP_IN_DIR}/POSCAR_fit_symm_s1")
s2 = Structure.from_file(f"{VASP_IN_DIR}/POSCAR_fit_symm_s2")

len(sm.group_structures([s1, s2]))                   # 1 group
len(sm.group_structures([s2, s1]))                   # 2 groups   <-- same inputs
len(sm.group_structures([s1, s2], symmetric=True))   # 2 groups
len(sm.group_structures([s2, s1], symmetric=True))   # 2 groups

Using test-files/io/vasp/inputs/POSCAR_fit_symm_s1 and _s2, from tests/core/test_structure_matcher.py:529-537.

This PR threads a symmetric kwarg through to the fit call so callers that need an order-independent
grouping can ask for one. It defaults to False, so no existing caller changes behaviour, and it is
ignored under anonymous=True since fit_anonymous has no symmetric mode. One test added.

Motivation: MaterialsProjectDFTMixingScheme groups GGA and r2SCAN structures this way, and the
asymmetry makes its phase diagrams depend on PYTHONHASHSEED — see materialsproject/pymatgen#3113 and
the follow-up PR (I'll be raising now) to materialsproject/pymatgen#4703, which passes symmetric=True here. Over the 120 permutations of the pre-group in that bug, the current default yields 3 distinct groupings and symmetric=True yields 1, at 1.04x runtime for the full pipeline.

Note this does not make greedy grouping order-independent in general — a symmetric relation can still be non-transitive — but it removes the directional class of it at least.

Checklist

  • Tests for the affected code pass locally (e.g. uv run pytest tests/core -k lattice
    for a lattice change — the full suite runs in CI)
  • Lint passes: uv run ruff check . && uv run ruff format --check .

Breaking changes?

  • This PR contains breaking changes (removals/renames, signature or
    behavior changes, changed defaults/output, dropped Python versions, ...).
    If so, prefix the title with [breaking] and describe the change and
    migration steps under ## Breaking Changes below.

Breaking Changes

@kavanase
kavanase requested a review from shyuep as a code owner August 24, 2026 15:49

@shyuep shyuep left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated PR review generated by Claude (posted via @shyuep's scheduled review routine)

Clean, minimal change. The order-dependence of group_structures from directional fit() is a real and long-standing footgun (cf. materialsproject/pymatgen#3113), and threading symmetric through with a False default preserves existing behavior. Docstring correctly notes the kwarg is ignored under anonymous=True and that greedy grouping remains non-transitive in general.

Test reuses the existing asymmetric POSCAR pair and covers both orderings — good. All CI green.

One minor note: symmetric=True roughly doubles the fit cost per pair; the 1.04x pipeline figure in the description is reassuring, so no action needed. LGTM.

@shyuep
shyuep merged commit cc61f10 into materialsproject:main Aug 30, 2026
5 checks passed
@shyuep

shyuep commented Aug 30, 2026

Copy link
Copy Markdown
Member

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants