Skip to content

Commit 36d5528

Browse files
feat: 添加SPG库基础功能与示例
新增SPG库核心模块,包括代数基础、群操作、空间与自旋操作定义。添加测试用例和演示示例,展示磁对称性分析与物理性质验证功能。包含文档说明与CI工作流配置。
0 parents  commit 36d5528

File tree

19 files changed

+758
-0
lines changed

19 files changed

+758
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Lean Action CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
workflow_dispatch:
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v5
14+
- uses: leanprover/lean-action@v1

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/.lake

Demo/Altermagnet.lean

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import SPG.Algebra.Basic
2+
import SPG.Algebra.Group
3+
import SPG.Geometry.SpatialOps
4+
import SPG.Geometry.SpinOps
5+
import SPG.Interface.Notation
6+
7+
namespace Demo.Altermagnet
8+
9+
open SPG
10+
open SPG.Geometry.SpatialOps
11+
open SPG.Geometry.SpinOps
12+
open SPG.Interface
13+
open SPG.Algebra
14+
15+
-- 1. Generators for D4h altermagnet
16+
def mat_4_z : Matrix (Fin 3) (Fin 3) ℚ := ![![0, -1, 0], ![1, 0, 0], ![0, 0, 1]]
17+
def mat_inv : Matrix (Fin 3) (Fin 3) ℚ := ![![ -1, 0, 0], ![0, -1, 0], ![0, 0, -1]]
18+
19+
-- Generators
20+
-- C4z * T : The key altermagnetic symmetry
21+
-- C2x : Standard rotation
22+
-- I : Inversion
23+
def gen_C4z_TR : SPGElement := Op[mat_4_z, ^-1]
24+
def gen_C2x : SPGElement := Op[mat_2_x, ^1]
25+
def gen_Inv : SPGElement := Op[mat_inv, ^1]
26+
27+
def Altermagnet_Group : List SPGElement := generate_group [gen_C4z_TR, gen_C2x, gen_Inv]
28+
29+
-- 2. Hamiltonian Analysis
30+
-- We want to find H(k) ~ c_ij k_i k_j terms allowed by symmetry.
31+
-- General form: H(k) = sum_{i,j} A_{ij} k_i k_j
32+
-- Symmetry constraint: g H(k) g^{-1} = H(g k)
33+
-- For spin-independent hopping (kinetic energy), H is a scalar in spin space (Identity).
34+
-- But altermagnetism involves spin-dependent terms.
35+
-- Altermagnet Hamiltonian usually looks like: H = (k^2 terms) * I_spin + (k-dependent field) * sigma
36+
-- Let's analyze terms of form: k_a k_b * sigma_c
37+
38+
-- Basis for quadratic k terms (k_x^2, k_y^2, k_z^2, k_x k_y, k_y k_z, k_z k_x)
39+
inductive QuadTerm
40+
| xx | yy | zz | xy | yz | zx
41+
deriving Repr, DecidableEq, Inhabited
42+
43+
def eval_quad (q : QuadTerm) (k : Vec3) : ℚ :=
44+
match q with
45+
| .xx => k 0 * k 0
46+
| .yy => k 1 * k 1
47+
| .zz => k 2 * k 2
48+
| .xy => k 0 * k 1
49+
| .yz => k 1 * k 2
50+
| .zx => k 2 * k 0
51+
52+
def all_quads : List QuadTerm := [.xx, .yy, .zz, .xy, .yz, .zx]
53+
54+
-- Basis for spin matrices (sigma_x, sigma_y, sigma_z)
55+
inductive SpinComp
56+
| I | x | y | z
57+
deriving Repr, DecidableEq, Inhabited
58+
59+
-- Action on k-vector (spatial part)
60+
def act_on_k (g : SPGElement) (k : Vec3) : Vec3 :=
61+
Matrix.mulVec g.spatial k
62+
63+
-- Action on spin component (spin part)
64+
-- sigma_prime = U sigma U^dagger
65+
-- Since our spin matrices are +/- I, the conjugation is trivial?
66+
-- WAIT. The user wants "d-wave altermagnet".
67+
-- In altermagnets, the spin symmetry is usually non-trivial (e.g. spin flip).
68+
-- But our SPGElement definition only supports spin matrices as "numbers" (Matrix 3x3).
69+
-- Currently `spin` is just +/- I.
70+
-- If spin part is just +/- I (Time Reversal), then:
71+
-- T sigma T^{-1} = - sigma (Time reversal flips spin)
72+
-- So if g.spin = -I (Time Reversal), the spin vector flips.
73+
-- If g.spin = I, spin vector stays.
74+
75+
def act_on_spin (g : SPGElement) (s : SpinComp) : SpinComp :=
76+
if g.spin == spin_neg_I then -- Time Reversal
77+
match s with
78+
| .I => .I -- Identity matrix is T-even
79+
| _ => s -- This is wrong. T sigma T^-1 = -sigma.
80+
-- But we represent "basis elements". We need a coefficient sign.
81+
-- Let's handle sign separately.
82+
-- s -- Just return component, sign handled in `check_symmetry`
83+
else
84+
s
85+
86+
def spin_sign (g : SPGElement) (s : SpinComp) : ℚ :=
87+
if g.spin == spin_neg_I then
88+
match s with
89+
| .I => 1
90+
| _ => -1 -- Spin flips under Time Reversal
91+
else
92+
1
93+
94+
-- Check if a term (Quad * Spin) is invariant under the group
95+
-- Term: C * Q(k) * S
96+
-- Transform: C * Q(g^-1 k) * (g S g^-1)
97+
-- We need Q(g^-1 k) * (spin_sign) == Q(k) for all g.
98+
-- Actually, let's just checking specific terms.
99+
100+
def check_invariant (q : QuadTerm) (s : SpinComp) : Bool :=
101+
Altermagnet_Group.all fun g =>
102+
-- Symmetry constraint: H(k) = U H(g^-1 k) U^dagger
103+
-- H(k) = f(k) * sigma
104+
-- U f(g^-1 k) sigma U^dagger = f(g^-1 k) * (U sigma U^dagger)
105+
-- So we need: f(k) * sigma = f(g^-1 k) * (sigma_transformed)
106+
-- Here sigma_transformed = s * spin_sign(g)
107+
-- And f(k) is quadratic form.
108+
109+
-- Let's test invariance on a set of random k-points to avoid accidental zeros
110+
let test_ks : List Vec3 := [![1, 0, 0], ![0, 1, 0], ![0, 0, 1], ![1, 1, 0], ![1, 0, 1], ![0, 1, 1], ![1, 2, 3]]
111+
112+
test_ks.all fun k =>
113+
-- Calculate g^-1 k. Since our group is finite and closed, g^-1 is in group.
114+
-- But for checking invariance, checking H(g k) = g H(k) g^-1 is equivalent.
115+
-- Let's check: H(g k) = g H(k) g^-1
116+
-- LHS: f(g k) * sigma
117+
-- RHS: g (f(k) * sigma) g^-1 = f(k) * (g sigma g^-1) = f(k) * sigma * spin_sign(g)
118+
119+
let val_gk := eval_quad q (act_on_k g k)
120+
let val_k := eval_quad q k
121+
let s_sgn := spin_sign g s
122+
123+
-- We need: val_gk == val_k * s_sgn
124+
val_gk == val_k * s_sgn
125+
126+
def find_invariants : List (QuadTerm × SpinComp) :=
127+
let terms := (all_quads.product [.I, .x, .y, .z])
128+
-- Also consider symmetric combinations like (kx^2 + ky^2) and antisymmetric (kx^2 - ky^2)
129+
-- Currently we only check pure basis terms.
130+
-- But (kx^2 + ky^2) * I should be invariant.
131+
-- Let's manually check (kx^2 + ky^2) * I and (kx^2 - ky^2) * sigma_z?
132+
-- Or better, construct a linear combination solver?
133+
-- For now, let's just stick to pure basis.
134+
-- If kx^2 and ky^2 transform into each other, neither is invariant alone.
135+
-- But their sum might be.
136+
-- To properly find Hamiltonian, we need representation theory (projectors).
137+
-- Simplification: Check "Is kx^2 + ky^2 invariant?" explicitly.
138+
139+
let simple_invariants := terms.filter fun (q, s) => check_invariant q s
140+
simple_invariants
141+
142+
-- 3. ICE Symbol Output (Simplistic)
143+
-- We just print generators for now, as full ICE symbol logic is complex.
144+
def ice_symbol : String :=
145+
"4'22 (D4h magnetic)" -- Placeholder, deriving from generators
146+
147+
end Demo.Altermagnet
148+
149+
def main : IO Unit := do
150+
IO.println s!"Generated Group Size: {Demo.Altermagnet.Altermagnet_Group.length}"
151+
IO.println s!"ICE Symbol (Approx): {Demo.Altermagnet.ice_symbol}"
152+
IO.println "Allowed Quadratic Hamiltonian Terms H(k):"
153+
154+
let invariants := Demo.Altermagnet.find_invariants
155+
for (q, s) in invariants do
156+
let q_str := match q with
157+
| .xx => "kx^2" | .yy => "ky^2" | .zz => "kz^2"
158+
| .xy => "kx ky" | .yz => "ky kz" | .zx => "kz kx"
159+
let s_str := match s with
160+
| .I => "I" | .x => "σx" | .y => "σy" | .z => "σz"
161+
IO.println s!" {q_str} * {s_str}"
162+
163+
-- Manually check d-wave altermagnet term: (kx^2 - ky^2) * sigma_z?
164+
-- Or kx ky * sigma_z ?
165+
-- Let's define a custom checker for kx^2 - ky^2
166+
let check_custom (f : SPG.Vec3 → ℚ) (s : Demo.Altermagnet.SpinComp) : Bool :=
167+
let test_ks : List SPG.Vec3 := [![1, 0, 0], ![0, 1, 0], ![0, 0, 1], ![1, 1, 0], ![1, 0, 1], ![0, 1, 1], ![1, 2, 3]]
168+
test_ks.all fun k =>
169+
-- Re-implement loop
170+
Demo.Altermagnet.Altermagnet_Group.all fun g =>
171+
let val_gk := f (Demo.Altermagnet.act_on_k g k)
172+
let val_k := f k
173+
let s_sgn := Demo.Altermagnet.spin_sign g s
174+
val_gk == val_k * s_sgn
175+
176+
let kx2_minus_ky2 (k : SPG.Vec3) : ℚ := k 0 * k 0 - k 1 * k 1
177+
let kx2_plus_ky2 (k : SPG.Vec3) : ℚ := k 0 * k 0 + k 1 * k 1
178+
179+
if check_custom kx2_minus_ky2 .z then
180+
IO.println " (kx^2 - ky^2) * σz [Altermagnetic d-wave term!]"
181+
182+
if check_custom kx2_plus_ky2 .I then
183+
IO.println " (kx^2 + ky^2) * I [Standard kinetic term]"

README.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# SPG (Spin Point Groups) Library
2+
3+
SPG is a Lean 4 library for analyzing Spin Point Groups, Magnetic Point Groups (MPGs), and symmetry breaking phenomena in condensed matter physics. It provides tools to define magnetic symmetries, generate group closures, and verify physical properties such as allowed electric polarization.
4+
5+
## Installation
6+
7+
Add the following dependency to your `lakefile.lean`:
8+
9+
```lean
10+
require SPG from git
11+
"https://github.com/tsurumi-yizhou/SPG.git"
12+
```
13+
14+
Then update dependencies:
15+
16+
```bash
17+
lake update
18+
```
19+
20+
## Usage Guide
21+
22+
This section demonstrates how to use the library to analyze magnetic symmetries.
23+
24+
### 1. Import Modules
25+
26+
Import the main library to access all core functionalities:
27+
28+
```lean
29+
import SPG
30+
31+
open SPG
32+
open SPG.Interface
33+
open SPG.Algebra
34+
open SPG.Physics
35+
open SPG.Geometry.SpatialOps
36+
```
37+
38+
### 2. Define Group Generators
39+
40+
Use the `Op[spatial, spin]` syntax to define group elements.
41+
* `^1`: Identity spin operation (non-magnetic).
42+
* `^-1`: Time-reversal operation (spin flip).
43+
44+
```lean
45+
-- Example: 4-fold rotoinversion along z (non-magnetic)
46+
def g1 : SPGElement := Op[mat_4bar_z, ^1]
47+
48+
-- Example: 2-fold rotation along x combined with time-reversal
49+
def g2 : SPGElement := Op[mat_2_x, ^-1]
50+
```
51+
52+
### 3. Generate Group Closure
53+
54+
Use `generate_group` to compute the full group from a set of generators.
55+
56+
```lean
57+
def my_group : List SPGElement := generate_group [g1, g2]
58+
59+
-- Check group order
60+
#eval my_group.length
61+
```
62+
63+
### 4. Symmetry Breaking Analysis
64+
65+
Given a magnetic ordering vector (Neel vector), compute the Magnetic Point Group (MPG). The MPG consists of all elements in the original group that leave the magnetic vector invariant.
66+
67+
```lean
68+
def neel_vector : Vec3 := ![1, 1, 0]
69+
70+
-- Compute the Magnetic Point Group
71+
def my_mpg : List SPGElement := get_mpg my_group neel_vector
72+
73+
-- Check the size of the MPG
74+
#eval my_mpg.length
75+
```
76+
77+
### 5. Physical Property Verification
78+
79+
Verify if the resulting symmetry group allows specific physical properties, such as spontaneous polarization along the z-axis.
80+
81+
```lean
82+
-- Returns true if z-polarization is allowed, false otherwise
83+
#eval allows_z_polarization my_mpg
84+
```
85+
86+
### 6. Formal Proof
87+
88+
Physical conclusions can be formally verified using `native_decide`.
89+
90+
```lean
91+
theorem polarization_allowed :
92+
(allows_z_polarization my_mpg) = true := by
93+
native_decide
94+
```
95+
96+
## Core Modules
97+
98+
* **SPG.Interface.Notation**: Syntax definitions for `Op[...]`, `^1`, etc.
99+
* **SPG.Algebra.Group**: Algorithms for finite group generation.
100+
* **SPG.Physics.SymmetryBreaking**: Functions for MPG extraction and property verification.
101+
* **SPG.Geometry.SpatialOps**: Predefined spatial operation matrices (e.g., `mat_4bar_z`).
102+
* **SPG.Demo.Altermagnet**: Example implementation for d-wave altermagnet.
103+
104+
## Notes
105+
106+
* **Precision**: All matrix and vector operations use `Rational` numbers (``) to ensure exact results and decidability.
107+
* **Scope**: The `generate_group` function is optimized for finite Point Groups.
108+
109+
## Acknowledgments
110+
111+
Special thanks to **Gemini 3** for the contributions to the code structure and implementation details.

SPG.lean

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import SPG.Algebra.Basic
2+
import SPG.Algebra.Actions
3+
import SPG.Algebra.Group
4+
import SPG.Geometry.SpatialOps
5+
import SPG.Geometry.SpinOps
6+
import SPG.Physics.SymmetryBreaking
7+
import SPG.Data.ICE_Notation
8+
import SPG.Data.Tetragonal
9+
import SPG.Interface.Notation
10+
11+
-- Re-export common namespaces for easy usage
12+
-- When users `import SPG`, they get access to all core modules.

SPG/Algebra/Actions.lean

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import SPG.Algebra.Basic
2+
import Mathlib.Data.Matrix.Basic
3+
import Mathlib.Algebra.Module.Basic
4+
import Mathlib.Data.Rat.Defs
5+
import Mathlib.Algebra.Ring.Basic
6+
import Mathlib.Algebra.Field.Defs
7+
import Mathlib.Algebra.Ring.Rat
8+
9+
namespace SPG
10+
11+
def magnetic_action (g : SPGElement) (v : Vec3) : Vec3 :=
12+
Matrix.mulVec g.spin (Matrix.mulVec g.spatial v)
13+
14+
def electric_action (g : SPGElement) (v : Vec3) : Vec3 :=
15+
Matrix.mulVec g.spatial v
16+
17+
end SPG

SPG/Algebra/Basic.lean

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import Mathlib.Data.Matrix.Basic
2+
import Mathlib.Algebra.Ring.Rat
3+
4+
namespace SPG
5+
6+
abbrev Vec3 := Fin 3 → ℚ
7+
8+
structure SPGElement where
9+
spatial : Matrix (Fin 3) (Fin 3) ℚ
10+
spin : Matrix (Fin 3) (Fin 3) ℚ
11+
deriving DecidableEq, Inhabited
12+
13+
instance : Mul SPGElement where
14+
mul a b := { spatial := a.spatial * b.spatial, spin := a.spin * b.spin }
15+
16+
def matrix_repr (m : Matrix (Fin 3) (Fin 3) ℚ) : Std.Format :=
17+
let rows := List.range 3 |>.map (fun i =>
18+
let row := List.range 3 |>.map (fun j =>
19+
match i, j with
20+
| 0, 0 => repr (m 0 0)
21+
| 0, 1 => repr (m 0 1)
22+
| 0, 2 => repr (m 0 2)
23+
| 1, 0 => repr (m 1 0)
24+
| 1, 1 => repr (m 1 1)
25+
| 1, 2 => repr (m 1 2)
26+
| 2, 0 => repr (m 2 0)
27+
| 2, 1 => repr (m 2 1)
28+
| 2, 2 => repr (m 2 2)
29+
| _, _ => Std.Format.text "error"
30+
)
31+
Std.Format.text s!"{row}"
32+
)
33+
Std.Format.joinSep rows (Std.Format.text "\n")
34+
35+
instance : Repr SPGElement where
36+
reprPrec s _ :=
37+
Std.Format.text "SPGElement(\n spatial: " ++ matrix_repr s.spatial ++ Std.Format.text ",\n spin: " ++ matrix_repr s.spin ++ Std.Format.text "\n)"
38+
39+
40+
end SPG

0 commit comments

Comments
 (0)