diff --git a/qpms/qpms_c.pyx b/qpms/qpms_c.pyx index 17dd96d..2a24556 100644 --- a/qpms/qpms_c.pyx +++ b/qpms/qpms_c.pyx @@ -1105,11 +1105,120 @@ cdef class CTMatrix: # N.B. there is another type called TMatrix in tmatrices.py # Maybe not totally needed after all, as np.array(T[...]) should be equivalent and not longer return np.array(self.m, copy=True) +cdef char *make_c_string(pythonstring): + ''' + Copies contents of a python string into a char[] + (allocating the memory with malloc()) + ''' + bytestring = pythonstring.encode('UTF-8') + cdef Py_ssize_t n = len(bytestring) + cdef char *s + s = malloc(n+1) + if not s: + raise MemoryError + s[:] = bytestring + s[n] = 0 + return s + cdef class FinitePointGroup: ''' Wrapper over the qpms_finite_group_t structure. + + TODO more functionality to make it better usable in Python + (group element class at least) ''' - pass + cdef readonly bint owns_data + cdef qpms_finite_group_t *G + + def __cinit__(self, info): + '''Constructs a FinitePointGroup from PointGroupInfo''' + # TODO maybe I might use a try..finally statement to avoid leaks + # First, generate all basic data from info + permlist = list(info.permgroup.elements) + cdef int order = len(permlist) + permindices = {perm: i for i, perm in enumerate(permlist)} # 'invert' permlist + identity = self.permgroup.identity + self.G = malloc(sizeof(qpms_finite_group_t)) + if not self.G: raise MemoryError + self.G[0].name = make_c_string(info.name) + self.G[0].order = order + self.G[0].idi = permindices[identity] + self.G[0].mt = malloc(sizeof(qpms_gmi_t) * order * order) + if not self.G[0].mt: raise MemoryError + for i in range(order): + for j in range(order): + self.G[0].mt[i*order + j] = permindices[permlist[i] * permlist[j]] + self.G[0].invi = malloc(sizeof(qpms_gmi_t) * order) + if not self.G[0].invi: raise MemoryError + for i in range(order): + self.G[0].invi[i] = permindices[permlist[i]**-1] + self.G[0].ngens = len(info.permgroupgens) + self.G[0].gens = malloc(sizeof(qpms_gmi_t) * self.G[0].ngens) + if not self.G[0].gens: raise MemoryError + for i in range(self.G[0].ngens): + self.G[0].gens[i] = permindices[info.groupgens[i]] + self.G[0].permrep = calloc(order, sizeof(char *)) + if not self.G[0].permrep: raise MemoryError + for i in range(order): + self.G[0].permrep[i] = make_c_string(str(permlist[i])) + if not self.G[0].permrep[i]: raise MemoryError + self.G[0].permrep_nelem = info.permgroup.degree + if info.rep3d is not None: + self.G[0].rep3d = malloc(order * sizeof(qpms_irot3_t)) + for i in range(order): + self.G[0].rep3d[i] = info.rep3d[permlist[i]].qd + self.G[0].nirreps = len(info.irreps) + self.G[0].irreps = calloc(self.G[0].nirreps, sizeof(qpms_finite_group_irrep_t)) + if not self.G[0].irreps: raise MemoryError + cdef int dim + for iri, (irname, irrep) in enumerate(info.irreps.items()): + is1d = isinstance(irrep[identity], (int, float, complex)) + dim = 1 if is1d else irrep[identity].shape[0] + self.G[0].irreps[iri].dim = dim + self.G[0].irreps[iri].name = make_c_string(irname) + if not self.G[0].irreps[iri].name: raise MemoryError + self.G[0].irreps[iri].m = malloc(dim*dim*sizeof(cdouble)*order) + if not self.G[0].irreps[iri].m: raise MemoryError + if is1d: + for i in range(order): + self.G[0].irreps[iri].m[i] = irrep[permlist[i]] + else: + for i in range(order): + for row in range(dim): + for col in range(dim): + self.G[0].irreps[iri].m[i*dim*dim + row*dim + col] = irrep[permlist[i]][row,col] + self.owns_data = True + + def __dealloc__(self): + cdef qpms_gmi_t order + if self.owns_data: + if self.G: + order = self.G[0].order + free(self.G[0].name) + free(self.G[0].mt) + free(self.G[0].invi) + free(self.G[0].gens) + if self.G[0].permrep: + for i in range(order): free(self.G[0].permrep[i]) + free(self.G[0].permrep) + if self.G[0].elemlabels: # this is not even contructed right now + for i in range(order): free(self.G[0].elemlabels[i]) + if self.G[0].irreps: + for iri in range(self.G[0].nirreps): + free(self.G[0].irreps[iri].name) + free(self.G[0].irreps[iri].m) + free(self.G[0].irreps) + free(self.G) + self.G = 0 + self.owns_data = False + +cdef class FinitePointGroupElement: + '''TODO''' + cdef readonly FinitePointGroup G + cdef readonly qpms_gmi_t gmi + def __cinit__(self, FinitePointGroup G, qpms_gmi_t gmi): + self.G = G + self.gmi = gmi cdef class Particle: ''' diff --git a/qpms/qpms_cdefs.pxd b/qpms/qpms_cdefs.pxd index 9d20fea..f3c3ca1 100644 --- a/qpms/qpms_cdefs.pxd +++ b/qpms/qpms_cdefs.pxd @@ -70,6 +70,9 @@ cdef extern from "qpms_types.h": QPMS_VSWF_ELECTRIC QPMS_VSWF_MAGNETIC QPMS_VSWF_LONGITUDINAL + ctypedef int qpms_gmi_t + ctypedef int qpms_iri_t + ctypedef const char * qpms_permutation_t # maybe more if needed cdef extern from "indexing.h": @@ -130,6 +133,26 @@ cdef extern from "wigner.h": qpms_irot3_t qpms_irot3_mult(qpms_irot3_t p, qpms_irot3_t q) qpms_irot3_t qpms_irot3_pow(qpms_irot3_t p, int n) +cdef extern from "groups.h": + struct qpms_finite_group_irrep_t: + int dim + char *name + cdouble *m + struct qpms_finite_group_t: + char *name + qpms_gmi_t order + qpms_gmi_t idi + qpms_gmi_t *mt + qpms_gmi_t *invi + qpms_gmi_t *gens + int ngens + qpms_permutation_t *permrep + char **elemlabels + int permrep_nelem + qpms_irot3_t *rep3d + qpms_iri_t nirreps + qpms_finite_group_irrep_t *irreps + cdef extern from "symmetries.h": cdouble *qpms_zflip_uvswi_dense(cdouble *target, const qpms_vswf_set_spec_t *bspec) cdouble *qpms_yflip_uvswi_dense(cdouble *target, const qpms_vswf_set_spec_t *bspec)