@@ -78,15 +78,41 @@ function exact_sparse_cohomology_basis(
7878 end
7979
8080 dn_mat = sparse (d_n_cols, d_n_rows, d_n_vals, d_n_n, d_n_m)
81- dense_dn = Matrix {Float64} (dn_mat)
8281
8382 quotient_basis = Vector {Vector{Int64}} ()
84- if size (dense_dn, 2 ) > 0
83+ if size (dn_mat, 2 ) > 0
84+ dense_dn = Matrix {Float64} (dn_mat)
8585 curr_rank = rank (dense_dn)
86+
8687 for vec in basis
8788 test_mat = hcat (dense_dn, Float64 .(vec))
8889 new_rank = rank (test_mat)
90+
91+ # Additional rigorous integer check
92+ # We append vec to Im(d_n). If it adds no rank, it's a coboundary.
93+ is_indep = false
8994 if new_rank > curr_rank
95+ try
96+ import AbstractAlgebra
97+ ZZ = AbstractAlgebra. ZZ
98+ int_test = AbstractAlgebra. matrix (ZZ, Matrix {Int} (hcat (Matrix (dn_mat), vec)))
99+ snf_test = AbstractAlgebra. snf (int_test)
100+ new_rank_int = count (x -> x != 0 , [snf_test[i, i] for i in 1 : min (size (int_test)... )])
101+
102+ int_base = AbstractAlgebra. matrix (ZZ, Matrix {Int} (Matrix (dn_mat)))
103+ snf_base = AbstractAlgebra. snf (int_base)
104+ base_rank_int = count (x -> x != 0 , [snf_base[i, i] for i in 1 : min (size (int_base)... )])
105+
106+ if new_rank_int > base_rank_int
107+ is_indep = true
108+ end
109+ catch
110+ # Fallback to float rank if AbstractAlgebra throws
111+ is_indep = true
112+ end
113+ end
114+
115+ if is_indep
90116 push! (quotient_basis, vec)
91117 dense_dn = test_mat
92118 curr_rank = new_rank
@@ -106,9 +132,12 @@ function group_ring_multiply(k1::Vector{String}, v1::Vector{Int}, k2::Vector{Str
106132 if g_str == " e" || g_str == " 1"
107133 return 0
108134 end
135+ m = match (r" g_?(\d +)(?:\^ -1)?" , g_str)
136+ if m === nothing
137+ throw (ArgumentError (" Invalid generator format: " * g_str))
138+ end
139+ val = parse (Int, m. captures[1 ])
109140 inv = endswith (g_str, " ^-1" )
110- base = inv ? replace (g_str[2 : end - 3 ], " g" => " " ) : replace (g_str, " g" => " " )
111- val = parse (Int, base)
112141 return inv ? - val : val
113142 end
114143
@@ -159,38 +188,5 @@ function abelianize_group(generators::Vector{String}, relations::Vector{String})
159188 pow = pow_str === nothing ? 1 : parse (Int, pow_str)
160189 M[i, gen_idx[base_w]] += pow
161190 end
162- end
163- end
164-
165- # SNF on M gives the structure of the abelianized group
166- U, S, V = svd (Float64 .(M))
167- s_vals = round .(Int, S[S .> 1e-10 ])
168- torsion = sort (s_vals[s_vals .> 1 ])
169-
170- rank = n_gens - length (s_vals)
171- return rank, torsion
172- end
173191
174- end
175- s = round .(Int, S[S .> tol])
176- torsion = sort (s_vals[s_vals .> 1 ])
177-
178- rank = n_gens - length (s_vals)
179- return rank, torsion
180- end
181- end
182-
183- end
184- end
185- end
186-
187- end
188- s = round .(Int, S[S .> tol])
189- torsion = sort (s_vals[s_vals .> 1 ])
190-
191- rank = n_gens - length (s_vals)
192- return rank, torsion
193- end
194- end
195-
196- end
192+ end # module SurgeryBackend
0 commit comments