Skip to content

Commit 8ca4ddc

Browse files
committed
merge main
2 parents b32f997 + 3c30c08 commit 8ca4ddc

25 files changed

+486
-443
lines changed

CHANGELOG.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
### Deprecated
1818

1919

20+
## [0.6.0] - 2026-03-06
21+
22+
### Added
23+
24+
- `Particle.is_massless` and `.is_lightlike` properties
25+
- introducing `minimal` shift type, as opposed to `generic`
26+
- `codim_upper_bound` optional parameter for `Particles.univariate_slice`
27+
- Tentative implementation of slices with approximate (p-adic) constraints
28+
- Tentative option `conjugation_acts_on_spin_indices` (boolean, package level) - unclear if it's correct to have two togglable behaviours
29+
- `massive_spins` in `Particles.cluster` allows setting left and right spin indices separately
30+
- tests for massive spin 1 polarizations
31+
32+
### Changed
33+
34+
- `Particles.subs` updated to support massive particles
35+
- `tr5` computation uses difference of traces `tr` rather than spinor strings to support arbitrary sequences of massless/massive legs
36+
- Allowing custom traces (`tr`) to be taken in lips ast evaluator
37+
- Improved `LipsIdeal` init, removed list vs tuple logic in favour of check of what variables appear in the polynomials (unparsed spinors, or parsed spinor components)
38+
- Migration of basic tools to pycoretools (e.g. `flatten`); cleanup of old python2.x remnants
39+
- `spin_index` split into `left_spin_index` and `right_spin_index`
40+
41+
### Fixed
42+
43+
- Fixed issue where p-adic slice would have constraints applied only at leading digit
44+
- Fixed issue where `all_symmetries` would not return conjugation permutation when all little group weights were zero.
45+
- Fixed issue where `Particles.compute` did not recognized `<` and `>` symbols as alternatives for unicode angle brackets in spinor chains.
46+
47+
### Deprecated
48+
49+
- `flatten` should be imported from pycoretools
50+
- `Field` should be imported from syngular
51+
52+
2053
## [0.5.1] - 2025-07-22
2154

2255
### Added
@@ -31,7 +64,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3164
- `seed` is no longer saved as a `Particles` attribute. WARNING: invalidates hash-tables.
3265
- `Particles.randomise` drasticaly simplified by using `field.random()` instead of handling all cases separately.
3366
- `spin_index` now saves both the position ('u' or 'd') and the value (1, 2, or all). If this was used explicitly it will require a simple fix to restore compatibility.
34-
- twistor functions, `randomise_twist` and `comp_twist_x` are not implemented in a covariant formulation.
67+
- twistor functions, `randomise_twist` and `comp_twist_x` are now implemented in a covariant formulation.
3568

3669
### Fixed
3770

@@ -171,7 +204,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
171204
- Numerical computation of Lorentz invariant spinor strings.
172205

173206

174-
[unreleased]: https://github.com/GDeLaurentis/lips/compare/v0.5.1...HEAD
207+
[unreleased]: https://github.com/GDeLaurentis/lips/compare/v0.6.0...HEAD
208+
[0.6.0]: https://github.com/GDeLaurentis/lips/compare/v0.5.1...v0.6.0
175209
[0.5.1]: https://github.com/GDeLaurentis/lips/compare/v0.5.0...v0.5.1
176210
[0.5.0]: https://github.com/GDeLaurentis/lips/compare/v0.4.5...v0.5.0
177211
[0.4.5]: https://github.com/GDeLaurentis/lips/compare/v0.4.4...v0.4.5

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![Coverage](https://img.shields.io/badge/Coverage-81%25-greenyellow?labelColor=2a2f35)](https://github.com/GDeLaurentis/lips/actions)
66
[![Docs](https://github.com/GDeLaurentis/lips/actions/workflows/cd_docs.yml/badge.svg?label=Docs)](https://gdelaurentis.github.io/lips/)
77
[![PyPI](https://img.shields.io/pypi/v/lips?label=PyPI)](https://pypi.org/project/lips/)
8-
[![PyPI Downloads](https://img.shields.io/pypi/dm/lips.svg?label=PyPI%20downloads)](https://pypi.org/project/lips/)
8+
[![PyPI Downloads](https://img.shields.io/pypi/dm/lips.svg?label=PyPI%20downloads)](https://pypistats.org/packages/lips)
99
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/GDeLaurentis/lips/HEAD)
1010
[![DOI](https://zenodo.org/badge/210320784.svg)](https://zenodo.org/doi/10.5281/zenodo.11518261)
1111
[![Python](https://img.shields.io/pypi/pyversions/lips?label=Python)](https://pypi.org/project/lips/)

lips/__init__.py

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,52 @@
1616
oParticles.set_pair(spinor_string_1, small_value_1, spinor_string_2, small_value_2)
1717
"""
1818

19-
from syngular import Field # noqa
20-
21-
from .version import __version__ # noqa
22-
from .particle import Particle # noqa
23-
from .particles import Particles # noqa
24-
from .tools import myException, ldot, flatten # noqa
25-
from .invariants import Invariants # noqa
19+
from .version import __version__
20+
from .particle import Particle
21+
from .particles import Particles
22+
from .tools import myException, ldot
23+
from .invariants import Invariants
2624

2725
spinor_convention = 'symmetric' # or 'asymmetric'
26+
conjugation_acts_on_spin_indices = False
27+
28+
__all__ = [
29+
"__version__",
30+
"Particle",
31+
"Particles",
32+
"myException",
33+
"ldot",
34+
"Invariants",
35+
]
36+
37+
38+
# Back-compatibility - to be removed
39+
40+
import warnings # noqa
41+
42+
43+
def __getattr__(name):
44+
if name in {"flatten", }:
45+
warnings.warn(
46+
f"lips.{name} is deprecated and will be removed in a future release; "
47+
f"use pycoretools.iterables.{name} (or: from pycoretools import {name}).",
48+
FutureWarning,
49+
stacklevel=2,
50+
)
51+
from pycoretools import iterables
52+
return getattr(iterables, name)
53+
if name in {"Field", }:
54+
warnings.warn(
55+
"lips.Field is deprecated and will be removed in a future release; "
56+
"use syngular.Field instead.",
57+
FutureWarning,
58+
stacklevel=2,
59+
)
60+
from syngular import Field
61+
return Field
62+
63+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
64+
65+
66+
def __dir__():
67+
return sorted(list(globals().keys()) + ["flatten", "Field", ])

lips/algebraic_geometry/covariant_ideal.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from collections import defaultdict
77

8-
from lips.tools import flatten
8+
from pycoretools import flatten
99
from lips.algebraic_geometry.tools import lips_covariant_symbols, lips_invariant_symbols, conversionIdeal
1010
from lips.algebraic_geometry.invariant_ideal import SpinorIdeal
1111
from syngular import Ideal, Ring
@@ -17,23 +17,36 @@
1717
class LipsIdeal(Ideal):
1818
"""Lorentz Covariant Ideal - based on spinor components."""
1919

20-
def __init__(self, ring_or_multiplicity, generators_or_covariants, momentum_conservation=None):
21-
"""Initialises a fully analytical Ideal, either from a tuple of covariants, or from a list of generators."""
20+
def __init__(self, ring_or_multiplicity, generators_or_covariants, momentum_conservation=None, verbose=False):
21+
"""Initialises a fully analytical Ideal, generators_or_covariants can be either already parsed in term spinor components or not."""
22+
from lips import Particles
2223

2324
if isinstance(ring_or_multiplicity, int):
2425
self.multiplicity = ring_or_multiplicity
26+
ring = Ring('0', lips_covariant_symbols(self.multiplicity), 'dp')
2527
elif isinstance(ring_or_multiplicity, Ring):
2628
self.multiplicity = len(ring_or_multiplicity.variables) // 2 // 2
29+
ring = ring_or_multiplicity
2730
else:
2831
raise Exception("Invalid LipsIdeal intialisation.")
2932

30-
if type(generators_or_covariants) is tuple:
31-
from lips import Particles
33+
try:
34+
if (isinstance(generators_or_covariants, (list, tuple)) and len(generators_or_covariants) == 0 and
35+
(momentum_conservation is True or momentum_conservation is None)):
36+
raise Exception("Add momentum conservation.")
37+
if (isinstance(generators_or_covariants, (list, tuple)) and len(generators_or_covariants) > 0 and
38+
any([symbol in eq for symbol in ['[', ']', '|', '<', '>', '⟨', '⟩', ] for eq in generators_or_covariants])):
39+
raise Exception("Needs parsing.")
40+
# already in the ring variables
41+
super().__init__(ring, generators_or_covariants)
42+
except Exception:
43+
# parse first the spinor expressions
3244
oParticles = Particles(self.multiplicity)
3345
oParticles.make_analytical_d()
3446
generators = []
3547
for covariant in generators_or_covariants:
36-
poly_or_polys = 4 * oParticles(covariant) # TODO: remove 4 * when https://github.com/sympy/sympy/pull/28139 is accepted
48+
# TODO: remove 4 * when https://github.com/sympy/sympy/pull/28139 is accepted
49+
poly_or_polys = 4 * oParticles(covariant)
3750
if hasattr(poly_or_polys, 'shape'):
3851
polys = flatten(poly_or_polys)
3952
for poly in polys:
@@ -42,17 +55,10 @@ def __init__(self, ring_or_multiplicity, generators_or_covariants, momentum_cons
4255
generators += [str(sympy.Poly(sympy.expand(poly_or_polys))).replace("Poly(", "").split(", ")[0]]
4356
if momentum_conservation is True or momentum_conservation is None:
4457
generators += [str(sympy.Poly(entry)).replace("Poly(", "").split(", ")[0] for entry in flatten(oParticles.total_mom)]
58+
super().__init__(ring, generators)
4559

46-
elif type(generators_or_covariants) is list:
47-
generators = generators_or_covariants
48-
49-
else:
50-
raise Exception("Invalid LipsIdeal intialisation.")
51-
52-
if isinstance(ring_or_multiplicity, int):
53-
super().__init__(Ring('0', lips_covariant_symbols(self.multiplicity), 'dp'), generators)
54-
elif isinstance(ring_or_multiplicity, Ring):
55-
super().__init__(ring_or_multiplicity, generators)
60+
if verbose:
61+
print("Initialized Lips Ideal:\n", repr(self))
5662

5763
def __contains__(self, covariant):
5864
"""Extends ideal membership to Lorentz covariant expressions computable with lips."""

lips/algebraic_geometry/particles_singular_variety.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import numpy
22

3+
from pycoretools import flatten
34
from pyadic import ModP, PAdic
45

5-
from ..tools import flatten
6-
76
from .covariant_ideal import LipsIdeal
87

98

lips/hardcoded_limits/particles_set.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
import numpy
1111
import re
1212

13-
from ..tools import flatten, pSijk, pDijk, pOijk, pPijk, pA2, pS2, pNB, ptr5, p5Bdiff, myException
13+
from pycoretools import flatten
14+
from ..tools import pSijk, pDijk, pOijk, pPijk, pA2, pS2, pNB, ptr5, p5Bdiff, myException
1415

1516

1617
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #

lips/hardcoded_limits/particles_set_pair.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# -*- coding: utf-8 -*-
2-
31
# ___ _ _ _ ___ _ ___ _
42
# | _ \__ _ _ _| |_(_)__| |___ ___ / __| ___| |_| _ \__ _(_)_ _
53
# | _/ _` | '_| _| / _| / -_|_-<_\__ \/ -_) _| _/ _` | | '_|
@@ -10,7 +8,8 @@
108
import numpy
119
import mpmath
1210

13-
from ..tools import flatten, pSijk, pDijk, pA2, pS2, p3B, pNB, myException
11+
from pycoretools import flatten
12+
from ..tools import pSijk, pDijk, pA2, pS2, p3B, pNB, myException
1413

1514

1615
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #

lips/invariants.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
#!/usr/bin/env python
2-
# -*- coding: utf-8 -*-
3-
41
# ___ _ _ _
52
# |_ _|_ ___ ____ _ _ _(_)__ _ _ _| |_ ___ __ _ ___ _ _ ___ _ _ __ _| |_ ___ _ _
63
# | || ' \ V / _` | '_| / _` | ' \ _(_-< / _` / -_) ' \/ -_) '_/ _` | _/ _ \ '_|

lips/particle.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
from copy import copy
1313
from sympy import NotInvertible
1414

15+
from pycoretools import flatten
1516
from syngular import Field
16-
1717
from pyadic.field_extension import FieldExtension
1818

19-
from .tools import MinkowskiMetric, LeviCivita, rand_frac, Pauli, Pauli_bar, flatten
19+
from .tools import MinkowskiMetric, LeviCivita, rand_frac, Pauli, Pauli_bar
2020

2121

2222
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
@@ -110,10 +110,10 @@ def __getitem__(self, key):
110110
return self.four_mom[key]
111111

112112
def __hash__(self):
113-
if abs(self.m2) <= self.field.tollerance:
113+
if self.is_massless:
114114
return hash(tuple([tuple(self.r_sp_d.flatten()), tuple(self.l_sp_d.flatten())]))
115115
else:
116-
return hash(tuple(self.r2_sp.flatten()))
116+
return hash(tuple([tuple(self.r2_sp.flatten()), tuple(self.r_sp_d.flatten()), tuple(self.l_sp_d.flatten())]))
117117

118118
# GETTERS and SETTERS
119119

@@ -299,6 +299,14 @@ def four_mom_d(self, temp_four_mom_d):
299299
self._l_sp_u = None
300300
self._l_sp_d = None
301301

302+
@property
303+
def spin_index(self):
304+
raise Exception("Spin index is set only - access left_spin_index and right_spin_index separately.")
305+
306+
@spin_index.setter
307+
def spin_index(self, value):
308+
self.left_spin_index = self.right_spin_index = value
309+
302310
# PUBLIC METHODS
303311

304312
def randomise(self, real_momentum=False):
@@ -331,13 +339,28 @@ def angles_for_squares(self):
331339
"""Flips left and right spinors."""
332340
if self.l_sp_d is not None and self.r_sp_d is not None: # massive scalars do not have these defined
333341
self._l_sp_d, self._r_sp_d = self._r_sp_d.T, self._l_sp_d.T
334-
if hasattr(self, 'spin_index'):
335-
if self.spin_index[0] == 'u':
342+
if hasattr(self, '_l_sp_d_all') and hasattr(self, '_r_sp_d_all'):
343+
self._l_sp_d_all, self._r_sp_d_all = self._r_sp_d_all.T, self._l_sp_d_all.T
344+
if lips.conjugation_acts_on_spin_indices and hasattr(self, 'right_spin_index') and hasattr(self, 'left_spin_index'):
345+
# see arXiv:2309.03323 - A.28 and A.29
346+
if self.left_spin_index[0] == 'u': # [i|
347+
self.left_spin_index = ('d',) + self.left_spin_index[1:]
336348
self._l_sp_d *= -1
337-
elif self.spin_index[0] == 'd':
349+
if hasattr(self, '_l_sp_d_all'):
350+
self._l_sp_d_all *= -1
351+
elif self.left_spin_index[0] == 'd':
352+
self.left_spin_index = ('u',) + self.left_spin_index[1:]
353+
else:
354+
raise Exception(f"Left spin index not understood: {self.left_spin_index[0]}")
355+
if self.right_spin_index[0] == 'd': # |i⟩
356+
self.right_spin_index = ('u',) + self.right_spin_index[1:]
338357
self._r_sp_d *= -1
358+
if hasattr(self, '_r_sp_d_all'):
359+
self._r_sp_d_all *= -1
360+
elif self.right_spin_index[0] == 'u':
361+
self.right_spin_index = ('d',) + self.right_spin_index[1:]
339362
else:
340-
raise Exception("Spin index not understood.")
363+
raise Exception(f"Right spin index not understood: {self.right_spin_index[0]}")
341364
self._sps_d_to_sps_u()
342365
self._r2_sp = self._r2_sp.T
343366
self._r2_sp_b = self._r2_sp_b.T
@@ -483,3 +506,9 @@ def m2(self):
483506
@property
484507
def m(self):
485508
return self.field.sqrt(self.lsq())
509+
510+
@property
511+
def is_massless(self):
512+
return (self.m2 in self.field and abs(self.m2) <= self.field.tollerance) or (self.m2 == 0)
513+
514+
is_lightlike = is_massless

0 commit comments

Comments
 (0)