"""
SymmetryAdaptedModel manages symmetry adapted multipole basis set for cluster or crystal system.
"""
from itertools import product
import sympy as sp
from gcoreutils.nsarray import NSArray
from multipie.tag.tag_list import TagList
from multipie.multipole.util.multipole_util import matrix_to_dict
from multipie.multipole.util.structure_samb_util import cs_list
from multipie.symmetry_operation.util.symmetry_operation_util import to_primitive
from multipie.model.util.symmetry_adapted_model_util import (
create_atomic_samb_set,
create_cluster_samb_set,
create_uniform_samb_set,
create_structure_samb_set,
create_z_samb_set,
create_zk_samb_set,
redefine_index,
)
from multipie import __version__
# ==================================================
header_str = """
=== SAMB (* only for crystal with fourier transform) ===
- info
- atomic : { "M_#" : ["amp_#"] }
- site_cluster : { "S_#" : ["smp_#"] }
- bond_cluster : { "B_#" : ["bmp_#"] }
- uniform : { "S_#"/"B_#" : ["ump_#"] }
- structure* : { "B_#" : ["kmp_#"] }
- Z : { ("M_#", "S_#"/"B_#") : ["z_#"] }
- version : MultiPie version
- harmonics : { head : [TagMultipole] }
- data
- atomic : { "amp_#" : ( TagMultipole, shape, [(i, j, matrix element)] ) }
- site_cluster : { "smp_#" : ( TagMultipole, [vector component] ) }
- bond_cluster : { "bmp_#" : ( TagMultipole, [vector component] ) }
- uniform* : { "ump_#" : ( TagMultipole, shape, [(i, j, matrix element)] ) }
- structure* : { "kmp_#" : (TagMultipole, "structure factor") }
- Z : {"z_#" : ( TagMultipole, [(coeff, "amp_#", "smp_#"/"bmp_#/ump_#")] ) }
- Zk* : {"z_#" : ( TagMultipole, [(coeff, "amp_#", "ump_#", "kmp_#")] ) }
"""
# ==================================================
matrix_header_str = """
== SAMB in full matrix form in real space (* only for crystal) ===
- model : model name.
- molecule : molecule or crystal ?
- group : (tag, detailed str)
- dimension : dimension of full matrix
- ket : ket basis list, orbital@site
- version : MultiPie version
- k_point* : representative k points
- k_path* : high-symmetry line in k space
- cell_site : { name_idx(pset): (position, SOs) }
- A* : transform matrix, [a1,a2,a3]
- matrix : { "z_#": "matrix"}
"""
# ==================================================
matrix_header_k_str = """
== SAMB in full matrix form with fourier transform ===
- model : model name.
- molecule : molecule or crystal ?
- group : (tag, detailed str)
- dimension : dimension of full matrix
- ket : ket basis list, orbital@site
- version : MultiPie version
- k_point : representative k points
- k_path : high-symmetry line in k space
- A : transform matrix, [a1,a2,a3]
- bond : { "bond_#": "vector" }
- matrix : { "z_#": "matrix" }
"""
# ==================================================
def _run(msg, mpm, func, *args, **kwargs):
mpm.log(f" * {msg} ... ", None, end="")
mpm.set_stamp()
res = func(*args, **kwargs)
mpm.log("done")
return res
# ==================================================
[docs]
class SymmetryAdaptedModel(dict):
"""
symmetry adapted multipole basis set for molecule or crystal.
"""
# Attributes:
# _model (dict): molecule or crystal model information.
# _mpm (MultiPieManager): MultiPie manager.
# _fourier_transform (bool): fourier transform combined multipole?
# _parallel (bool): use parallel code.
# _verbose (bool): verbose parallel info.
#
# ==================================================
def __init__(self, model, mpm, head):
"""
initialize the class.
Args:
model (dict): model information of cluster or crystal system.
mpm (MultiPieManager): MultiPie manager.
head (list or str): heads of SAMB to be created.
"""
super().__init__()
# model
self._model = model
self._mpm = mpm
self._parallel = self._mpm.parallel
self._verbose = self._mpm.verbose
toroidal_priority = model["info"]["generate"]["toroidal_priority"]
irrep = model["info"]["generate"]["irrep"]
site = model["data"]["site"]
cluster_site = model["data"]["cluster_site"]
bond = model["data"]["bond"]
cluster_bond = model["data"]["cluster_bond"]
cluster_atomic = model["data"]["cluster_atomic"]
atomic_braket = model["data"]["atomic_braket"]
alias = model["name"]["alias"]
spinful = model["info"]["spinful"]
is_phonon = model["info"]["generate"]["model_type"] == "phonon"
g = mpm.group
pg = mpm.point_group
# atomic
func = create_atomic_samb_set
args = [pg, atomic_braket, spinful, is_phonon, False]
atomic_info, atomic_data = _run("atomic", self._mpm, func, *args)
# site/bond-cluster
rep_site_dict = {cluster_tag: site[site_list[0]][0] for cluster_tag, site_list in cluster_site.items()}
rep_bond_dict = {cluster_tag: bond[bond_list[0]][0] for cluster_tag, bond_list in cluster_bond.items()}
func = create_cluster_samb_set
args = [g, rep_site_dict, rep_bond_dict, False]
site_cluster_info, site_cluster_data, bond_cluster_info, bond_cluster_data = _run(
"site/bond-cluster", self._mpm, func, *args
)
# uniform
if self._model["info"]["molecule"] or self._model["info"]["generate"].get("fourier_transform", False):
cluster_samb_set = {
S_i: [site_cluster_data[smp_i] for smp_i in lst] for S_i, lst in site_cluster_info.items()
}
cluster_samb_set |= {
B_i: [bond_cluster_data[bmp_i] for bmp_i in lst] for B_i, lst in bond_cluster_info.items()
}
braket_indexes_dict = {
cluster_tag: [site[site_tag][2] for site_tag in site_list]
for cluster_tag, site_list in cluster_site.items()
}
braket_indexes_dict |= {
cluster_tag: [bond[bond_tag][2] for bond_tag in bond_list]
for cluster_tag, bond_list in cluster_bond.items()
}
dim = len(site)
func = create_uniform_samb_set
args = [cluster_samb_set, braket_indexes_dict, dim]
uniform_info, uniform_data = _run("uniform", self._mpm, func, *args)
# Z
x_tag_dict = {(M_i, atomic_data[amp_i][0]): amp_i for M_i, lst in atomic_info.items() for amp_i in lst}
if self._model["info"]["molecule"]:
y_tag_dict = {(SB_i, uniform_data[ump_i][0]): ump_i for SB_i, lst in uniform_info.items() for ump_i in lst}
else:
y_tag_dict = {
(S_i, site_cluster_data[smp_i][0]): smp_i for S_i, lst in site_cluster_info.items() for smp_i in lst
}
y_tag_dict |= {
(B_i, bond_cluster_data[bmp_i][0]): bmp_i for B_i, lst in bond_cluster_info.items() for bmp_i in lst
}
cluster_site_bond = cluster_site | cluster_bond
braket_site_no_dict = {S_i: site[site_list[0]][2] for S_i, site_list in cluster_site.items()}
braket_site_no_dict |= {B_i: bond[bond_list[0]][2] for B_i, bond_list in cluster_bond.items()}
M_SB_list = []
for SB_i in cluster_site_bond.keys():
for _, _, M_i in cluster_atomic[braket_site_no_dict[SB_i]]:
M_SB_list.append((M_i, SB_i))
func = create_z_samb_set
args = [g, x_tag_dict, y_tag_dict, M_SB_list, atomic_braket, alias, toroidal_priority, False]
z_info, z_data = _run("Z", self._mpm, func, *args, head=head, irrep=irrep)
# info and data
self["info"] = {
"atomic": atomic_info,
"site_cluster": site_cluster_info,
"bond_cluster": bond_cluster_info,
}
self["data"] = {
"atomic": atomic_data,
"site_cluster": site_cluster_data,
"bond_cluster": bond_cluster_data,
}
if self._model["info"]["molecule"]:
self["info"] |= {"uniform": uniform_info}
self["data"] |= {"uniform": uniform_data}
self["info"] |= {"Z": z_info, "version": __version__}
self["data"] |= {"Z": z_data}
if not self._model["info"]["molecule"] and self._model["info"]["generate"]["fourier_transform"]:
self["info"] |= {"uniform": uniform_info}
self["data"] |= {"uniform": uniform_data}
self.fourier_transform()
if self._model["info"]["option"]["minimal_samb"]:
self._minimal_samb()
self["info"]["harmonics"] = self._harmonics_info()
# ==================================================
def _harmonics_info(self):
"""
convert combined multipoles from dictionary to numerical matrix form (real-space).
Args:
fmt (str, optional): sympy/value.
Returns:
dict: matrix form of combined multipoles, z_dict/z_full.
Note:
z_dict = { "z_#" : {(n1, n2, n3, a, b): matrix element}, R=(n1,n2,n3) is a lattice vector.
"""
atomic_data = self["data"]["atomic"]
site_cluster_data = self["data"]["site_cluster"]
bond_cluster_data = self["data"]["bond_cluster"]
uniform_data = self["data"].get("uniform", None)
structure_data = self["data"].get("structure", None)
head_list = ["Q", "G", "M", "T"]
harmonics_info = {"Q": [], "G": []}
for X in head_list:
data = atomic_data | site_cluster_data | bond_cluster_data
if uniform_data:
data |= uniform_data
if structure_data:
data |= structure_data
tag_list = TagList([tag for _, (tag, _) in data.items()]).select(head=X)
harmonics_list = sorted(set([tag.to_harmonics() for tag in tag_list]))
X = "G" if X == "M" else X
X = "Q" if X == "T" else X
harmonics_info[X] += [str(htag) for htag in harmonics_list]
harmonics_info = {"Q": sorted(set(harmonics_info["Q"])), "G": sorted(set(harmonics_info["G"]))}
return harmonics_info
# ==================================================
def _minimal_samb(self):
"""
delete unused samb and redefine the serial number of multipoles.
"""
molecule = self._model["info"]["molecule"]
atomic_info = self["info"]["atomic"]
site_cluster_info = self["info"]["site_cluster"]
bond_cluster_info = self["info"]["bond_cluster"]
z_info = self["info"]["Z"]
uniform_info = self["info"].get("uniform", None)
structure_info = self["info"].get("structure", None)
atomic_data = self["data"]["atomic"]
site_cluster_data = self["data"]["site_cluster"]
bond_cluster_data = self["data"]["bond_cluster"]
z_data = self["data"]["Z"]
uniform_data = self["data"].get("uniform", None)
structure_data = self["data"].get("structure", None)
zk_data = self["data"].get("Zk", None)
if site_cluster_data:
site_cluster_info, site_cluster_data, z_data = redefine_index(
site_cluster_info, site_cluster_data, z_data, molecule=molecule
)
if site_cluster_info:
init_idx = int(list(site_cluster_info.values())[-1][-1].split("_")[1]) + 1
else:
init_idx = 1
if bond_cluster_data:
bond_cluster_info, bond_cluster_data, z_data = redefine_index(
bond_cluster_info, bond_cluster_data, z_data, molecule=molecule, init_idx=init_idx
)
if molecule:
atomic_info, atomic_data, z_data = redefine_index(atomic_info, atomic_data, z_data, molecule=molecule)
uniform_info, uniform_data, z_data = redefine_index(uniform_info, uniform_data, z_data, molecule=molecule)
else:
if not self._model["info"]["generate"].get("fourier_transform", False):
atomic_info, atomic_data, z_data = redefine_index(atomic_info, atomic_data, z_data)
else:
_, _, z_data = redefine_index(atomic_info, atomic_data, z_data)
atomic_info, atomic_data, zk_data = redefine_index(atomic_info, atomic_data, zk_data)
uniform_info, uniform_data, zk_data = redefine_index(uniform_info, uniform_data, zk_data)
structure_info, structure_data, zk_data = redefine_index(structure_info, structure_data, zk_data)
self["info"] = {
"atomic": atomic_info,
"site_cluster": site_cluster_info,
"bond_cluster": bond_cluster_info,
}
self["data"] = {
"atomic": atomic_data,
"site_cluster": site_cluster_data,
"bond_cluster": bond_cluster_data,
}
if self._model["info"]["molecule"]:
self["info"] |= {"uniform": uniform_info}
self["data"] |= {"uniform": uniform_data}
self["info"] |= {"Z": z_info, "version": __version__}
self["data"] |= {"Z": z_data}
if not self._model["info"]["molecule"] and self._model["info"]["generate"]["fourier_transform"]:
self["info"] |= {"uniform": uniform_info}
self["data"] |= {"uniform": uniform_data}
self["info"] |= {"structure": structure_info}
self["data"] |= {"structure": structure_data}
self["data"] |= {"Zk": zk_data}
self["info"]["harmonics"] = self._harmonics_info()
# ==================================================
# ==================================================
[docs]
def create_dict(self):
"""
create dictionary containing information and data of atomic, site-cluster, bond-cluster,
uniform, (structure), Z(combined), Zk(fourier transform of Z).
Returns:
dict: information and data of multipole bases.
"""
info = self["info"]
atomic_data = {amp_i: (str(tag), *matrix_to_dict(m)) for amp_i, (tag, m) in self["data"]["atomic"].items()}
site_cluster_data = {smp_i: (str(tag), str(v)) for smp_i, (tag, v) in self["data"]["site_cluster"].items()}
bond_cluster_data = {bmp_i: (str(tag), str(v)) for bmp_i, (tag, v) in self["data"]["bond_cluster"].items()}
z_data = {z_i: (str(tag), [tuple(map(str, v)) for v in lst]) for z_i, (tag, lst) in self["data"]["Z"].items()}
data = {
"atomic": atomic_data,
"site_cluster": site_cluster_data,
"bond_cluster": bond_cluster_data,
}
if self._model["info"]["molecule"]:
uniform_data = {
ump_i: (str(tag), *matrix_to_dict(m)) for ump_i, (tag, m) in self["data"]["uniform"].items()
}
data |= {"uniform": uniform_data}
data |= {"Z": z_data}
if not self._model["info"]["molecule"] and self._model["info"]["generate"]["fourier_transform"]:
uniform_data = {
ump_i: (str(tag), *matrix_to_dict(m)) for ump_i, (tag, m) in self["data"]["uniform"].items()
}
structure_data = {
kmp_i: (str(tag), str(fk).replace("'", "")) for kmp_i, (tag, fk) in self["data"]["structure"].items()
}
zk_data = {
z_i: (str(tag), [tuple(map(str, v)) for v in lst]) for z_i, (tag, lst) in self["data"]["Zk"].items()
}
data |= {"uniform": uniform_data}
data |= {"structure": structure_data}
data |= {"Zk": zk_data}
return {"info": info, "data": data}
# ==================================================
[docs]
def create_matrix(self, fmt="sympy"):
"""
convert combined multipoles from dictionary to numerical matrix form (real-space).
Args:
fmt (str, optional): sympy/value.
Returns:
dict: matrix form of combined multipoles, z_dict/z_full.
Note:
z_dict = { "z_#" : {(n1, n2, n3, a, b): matrix element}, R=(n1,n2,n3) is a lattice vector.
"""
if fmt not in ["sympy", "value"]:
raise KeyError(f"unknown format = {fmt} is given.")
site = self._model["data"]["site"]
cluster_site = self._model["data"]["cluster_site"]
bond = self._model["data"]["bond"]
cluster_bond = self._model["data"]["cluster_bond"]
n_sgn_dict = {}
for B_i, bond_list in cluster_bond.items():
n_sgn_list = []
for bond_n in bond_list:
vec = bond[bond_n][3]
if "bond" in vec:
n = int(vec.split("_")[1])
else:
n = int(bond_n.split("_")[1])
if vec[0] == "-":
n_sgn_list.append((n, -1))
else:
n_sgn_list.append((n, +1))
n_sgn_dict[B_i] = n_sgn_list
cluster_atomic = self._model["data"]["cluster_atomic"]
atomic_braket = self._model["data"]["atomic_braket"]
alias = self._model["name"]["alias"]
dim_full = self._model["info"]["dimension"]
atomic_data = self["data"]["atomic"]
site_cluster_data = self["data"]["site_cluster"]
bond_cluster_data = self["data"]["bond_cluster"]
z_info, z_data = self["info"]["Z"], self["data"]["Z"]
z_samb = {}
z_samb["model"] = self._model["info"]["model"]
z_samb["molecule"] = self._model["info"]["molecule"]
z_samb["group"] = self._model["info"]["group"]
z_samb["dimension"] = self._model["info"]["dimension"]
z_samb["ket"] = self._model["info"]["ket"]
z_samb["cell_site"] = self._model["info"]["cell_site"]
z_samb["version"] = __version__
if not z_samb["molecule"]:
z_samb["k_point"] = self._model["info"]["k_point"]
z_samb["k_path"] = self._model["info"]["k_path"]
z_samb["A"] = self._model["detail"]["A"]
z_full = {}
for (_, M_i, SB_i), z_i_list in z_info.items():
bra_orb_list, ket_orb_list = atomic_braket[M_i]
dim_r, dim_c = len(bra_orb_list), len(ket_orb_list)
for z_i in z_i_list:
lst1 = z_data[z_i][1]
# site × atomic
if SB_i[0] == "S":
site_i_list = cluster_site[SB_i]
Z = sp.Matrix.zeros(dim_full, dim_full)
for c, amp_i, smp_i in lst1:
X = atomic_data[amp_i][1]
if self._model["info"]["molecule"]:
smp_i = smp_i.replace("u", "s")
v = list(site_cluster_data[smp_i][1])
for i in range(len(v)):
vi = v[i]
if vi == 0:
continue
bra_idx, ket_idx = site[site_i_list[i]][2]
for bra_no, ket_no, M_i_ in cluster_atomic[(bra_idx, ket_idx)]:
if M_i_ != M_i:
continue
Z[bra_no : bra_no + dim_r, ket_no : ket_no + dim_c] += c * vi * sp.Matrix(X)
if bra_orb_list != ket_orb_list:
Z = (Z + Z.adjoint()) / sp.sqrt(2)
Z = Z / Z.norm()
z_full[z_i] = {
(0, 0, 0, a, b): Z[a, b] for a in range(dim_full) for b in range(dim_full) if Z[a, b] != 0
}
# bond × atomic
else:
S1, S2, _, _ = alias[SB_i].split(":")
z_full[z_i] = {}
n_sgn_list = n_sgn_dict[SB_i]
bond_i_list = cluster_bond[SB_i]
for v in lst1:
c, amp_i, bmp_i = v
X = atomic_data[amp_i][1]
if self._model["info"]["molecule"]:
bmp_i = bmp_i.replace("u", "b")
v = list(bond_cluster_data[bmp_i][1])
for i in range(len(v)):
vi = v[i]
if vi == 0:
continue
n, sgn = n_sgn_list[i]
bra_idx, ket_idx = bond[bond_i_list[i]][2]
bv = sgn * NSArray(bond[f"bond_{n:03d}"][3], style="vector")
if not self._model["info"]["molecule"]:
lattice = self._model["info"]["group"][1].split("/")[1].replace(" ", "")[0]
bv = to_primitive(lattice, bv)
s1 = NSArray(list(site.values())[bra_idx][0], style="vector")
s2 = NSArray(list(site.values())[ket_idx][0], style="vector")
n1, n2, n3 = -(bv - (s1 - s2))
n1, n2, n3 = round(n1), round(n2), round(n3)
for bra_no, ket_no, M_i_ in cluster_atomic[(bra_idx, ket_idx)]:
if M_i_ != M_i:
continue
Z = sp.Matrix.zeros(dim_full, dim_full)
Z[bra_no : bra_no + dim_r, ket_no : ket_no + dim_c] += c * vi * sp.Matrix(X)
if S1 == S2 and bra_orb_list != ket_orb_list:
if bra_idx == ket_idx:
Z[ket_no : ket_no + dim_c, bra_no : bra_no + dim_r] += (
c * vi * sp.Matrix(X).adjoint()
)
else:
bra_no += dim_r
ket_no -= dim_r
Z[bra_no : bra_no + dim_c, ket_no : ket_no + dim_r] += (
c * vi * sp.Matrix(X).adjoint()
)
Z /= sp.sqrt(2)
for a in range(dim_full):
for b in range(dim_full):
z = sp.expand(Z[a, b])
if z == sp.S(0) or z == 0:
continue
if (n1, n2, n3, a, b) not in z_full[z_i]:
z_full[z_i][(n1, n2, n3, a, b)] = z / sp.sqrt(2)
z_full[z_i][(-n1, -n2, -n3, b, a)] = sp.conjugate(z) / sp.sqrt(2)
else:
z_full[z_i][(n1, n2, n3, a, b)] += z / sp.sqrt(2)
z_full[z_i][(-n1, -n2, -n3, b, a)] += sp.conjugate(z) / sp.sqrt(2)
if fmt == "value":
DIGIT = 14
z_full = {
z_i: {
k: str(round(complex(v).real, DIGIT) + round(complex(v).imag, DIGIT) * 1j)
for k, v in d.items()
if sp.expand(v) != 0
}
for z_i, d in z_full.items()
}
else:
z_full = {z_i: {k: str(v) for k, v in d.items() if sp.expand(v) != 0} for z_i, d in z_full.items()}
z_samb["matrix"] = z_full
return z_samb
# ==================================================
[docs]
def create_matrix_k(self, full=False, fmt="sympy"):
"""
convert combined multipoles from dictionary to numerical matrix form (momentum-space).
Args:
full (bool, optional): full matrix format ?
fmt (str, optional): sympy/value.
Returns:
dict: matrix form of combined multipoles, z_dict/z_full.
Note:
z_dict = { "z_#" : [(i, j, ""/c###/s###, v)] }
z_full = { "z_#" : NSArray(matrix) }
"""
if fmt not in ["sympy", "value"]:
raise KeyError(f"unknown format = {fmt} is given.")
molecule = self._model["info"]["molecule"]
cluster_atomic = self._model["data"]["cluster_atomic"]
atomic_braket = self._model["data"]["atomic_braket"]
alias = self._model["name"]["alias"]
dim_full = self._model["info"]["dimension"]
atomic_data = self["data"]["atomic"]
uniform_data = self["data"]["uniform"]
if molecule:
z_info, z_data = self["info"]["Z"], self["data"]["Z"]
else:
structure_data = self["data"]["structure"]
z_info, z_data = self["info"]["Z"], self["data"]["Zk"]
z_samb = {}
z_samb["model"] = self._model["info"]["model"]
z_samb["molecule"] = self._model["info"]["molecule"]
z_samb["group"] = self._model["info"]["group"]
z_samb["dimension"] = self._model["info"]["dimension"]
z_samb["ket"] = self._model["info"]["ket"]
z_samb["version"] = __version__
if not molecule:
z_samb["k_point"] = self._model["info"]["k_point"]
z_samb["k_path"] = self._model["info"]["k_path"]
z_samb["A"] = self._model["detail"]["A"]
bond = {}
for name, ex in self._model["data"]["bond"].items():
ex = ex[0].split("@")[0]
bond[name] = ex
z_samb["bond"] = bond
z_full = {}
for (_, M_i, SB_i), z_i_list in z_info.items():
if SB_i[0] == "S":
S1 = S2 = alias[SB_i]
else:
S1, S2, _, _ = alias[SB_i].split(":")
bra_orb_list, ket_orb_list = atomic_braket[M_i]
dim_r, dim_c = len(bra_orb_list), len(ket_orb_list)
for z_i in z_i_list:
lst1 = z_data[z_i][1]
Z = sp.Matrix.zeros(dim_full, dim_full)
for v in lst1:
if len(v) == 3:
c, amp_i, ump_i = v
F = 1
else:
c, amp_i, ump_i, kmp_i = v
F = structure_data[kmp_i][1]
X = atomic_data[amp_i][1]
U = uniform_data[ump_i][1]
for (bra_idx, ket_idx), lst2 in cluster_atomic.items():
u = U[bra_idx, ket_idx]
if u != 0:
for bra_no, ket_no, M_i_ in lst2:
if M_i_ != M_i:
continue
if S1 == S2 and bra_orb_list != ket_orb_list:
Z[bra_no : bra_no + dim_r, ket_no : ket_no + dim_c] += (
c * u * F * sp.Matrix(X) / sp.sqrt(2)
)
if bra_idx == ket_idx:
Z[ket_no : ket_no + dim_c, bra_no : bra_no + dim_r] += (
c * u * F * sp.Matrix(X).adjoint()
) / sp.sqrt(2)
else:
bra_no += dim_r
ket_no -= dim_r
Z[bra_no : bra_no + dim_c, ket_no : ket_no + dim_r] += (
c * u * F * sp.Matrix(X).adjoint()
) / sp.sqrt(2)
else:
Z[bra_no : bra_no + dim_r, ket_no : ket_no + dim_c] += c * u * F * sp.Matrix(X)
if not Z.is_hermitian:
Z = Z + Z.adjoint()
z_full[z_i] = sp.expand(Z)
DIGIT = 14
if full:
if fmt == "sympy":
z_full = {z_i: str(mat.tolist()) for z_i, mat in z_full.items()}
else:
z_full_val = {}
for z_i, Z in z_full.items():
Z_val = sp.Matrix.zeros(dim_full, dim_full)
for i, j in product(range(dim_full), range(dim_full)):
vij = Z[i, j]
if vij != 0:
if len(z_data[z_i][1][0]) == 3:
vij = complex(vij)
vij = round(vij.real, DIGIT) + round(vij.imag, DIGIT) * 1j
Z_val[i, j] += vij
else:
d = {csn: vij.coeff(csn) for csn in cs_list(vij, real=True)}
for csn, vij in d.items():
if vij != sp.S(0):
vij = complex(vij)
vij = round(vij.real, DIGIT) + round(vij.imag, DIGIT) * 1j
Z_val[i, j] += vij * csn
z_full_val[z_i] = Z_val
z_full = {z_i: str(NSArray(mat.tolist(), "matrix")) for z_i, mat in z_full_val.items()}
z_samb["matrix"] = z_full
return z_samb
else:
z_dict = {}
for z_i, Z in z_full.items():
mat = []
for i, j in product(range(dim_full), range(dim_full)):
vij = Z[i, j]
if vij != 0:
if len(z_data[z_i][1][0]) == 3:
mat.append((i, j, "", str(vij)))
else:
d = {str(csn): vij.coeff(csn) for csn in cs_list(vij, real=True)}
for csn_str, vij in d.items():
if vij != sp.S(0):
if fmt == "value":
vij = complex(vij)
vij = round(vij.real, DIGIT) + round(vij.imag, DIGIT) * 1j
mat.append((i, j, csn_str, str(vij)))
z_dict[z_i] = mat
z_samb["matrix"] = z_dict
return z_samb
# ==================================================
@classmethod
def _header(cls):
return header_str
# ==================================================
@classmethod
def _matrix_header_k(cls):
return matrix_header_k_str
# ==================================================
@classmethod
def _matrix_header(cls):
return matrix_header_str