/*! \file groups.h
 * \brief Point groups.
 *
 * Right now, the instances of qpms_finite_group_t are created at compilation time
 * from source code generated by Python script TODO (output groups.c)
 * and they are not to be constructed dynamically.
 *
 * In the end, I might want to have a special type for 3D point groups
 * or more specifically, for the closed subgroups of O(3), see
 * https://en.wikipedia.org/wiki/Point_groups_in_three_dimensions.
 * They consist of the seven infinite series of axial groups 
 * (characterized by the series index, the axis direction, 
 * and the index \a n of the \a n-fold rotational symmetry)
 * and the seven remaining point groups + the finite groups.
 * All off them have a quite limited number of generators
 * (max. 4?; CHECKME).
 * The goal is to have some representation that would enable to
 *   1. fully describe the symmetries of abstract T-matrices/nanoparticles,
 *   2. quickly determine e.g. whether one is a subgroup of another,
 *   3. have all the irreps,
 *   4. have all in C and without excessive external dependencies,
 * etc.
 */
#ifndef QPMS_GROUPS_H
#define QPMS_GROUPS_H

#include "qpms_types.h"
#include <assert.h>

/// To be used only in qpms_finite_group_t
struct qpms_finite_group_irrep_t {
	int dim; ///< Irrep dimension.
	char *name; ///< Irrep label.
	/// Irrep matrix data.
	/** The r-th row, c-th column of the representation of the i'th element is retrieved as
	 *  m[i * dim * dim + r * dim + c]
	 */
	complex double *m; 
};

/// A point group with its irreducible representations and some metadata.
/** 
 *  The structure of the group is given by the multiplication table \a mt.
 *
 *  Each element of the group has its index from 0 to order.
 *  The metadata about some element are then accessed using that index.
 *
 *  All members are in principle optional except \a order and \a mt.
 *
 *  Note: after changing this struct, don't forget to update the Python method
 *  SVWFPointGroupInfo.generate_c_source().
 */
typedef struct qpms_finite_group_t {
	char *name;
	qpms_gmi_t order; ///< Group order (number of elements)
	qpms_gmi_t idi; ///< Identity element index
	qpms_gmi_t *mt; ///< Group multiplication table. If c = a*b, then ic = mt[order * ia + ib].
	qpms_gmi_t *invi; ///< Group elem inverse indices.
	qpms_gmi_t *gens; ///< A canonical set of group generators.
	int ngens; ///< Number of the generators in gens;
	qpms_permutation_t *permrep; ///< Permutation representations of the elements.
	char **elemlabels; ///< Optional human readable labels for the group elements.
	int permrep_nelem; ///< Number of the elements over which the permutation representation acts.
	struct qpms_irot3_t *rep3d; ///< The quaternion representation of a 3D point group (if applicable).
	qpms_iri_t nirreps; ///< How many irreps does the group have
	struct qpms_finite_group_irrep_t *irreps; ///< Irreducible representations of the group.
} qpms_finite_group_t;

/// Group multiplication.
static inline qpms_gmi_t qpms_finite_group_mul(const qpms_finite_group_t *G,
		qpms_gmi_t a, qpms_gmi_t b) {
	assert(a < G->order);
	assert(b < G->order);
	return G->mt[G->order * a + b];
}

/// Group element inversion.
static inline qpms_gmi_t qpms_finite_group_inv(const qpms_finite_group_t *G,
		qpms_gmi_t a) {
	assert(a < G->order);
	return G->invi[a];
}

static inline _Bool qpms_iri_is_valid(const qpms_finite_group_t *G, qpms_iri_t iri) {
	return (iri > G->nirreps || iri < 0) ? 0 : 1;
}



/// NOT IMPLEMENTED Get irrep index by name.
qpms_iri_t qpms_finite_group_find_irrep_by_name(qpms_finite_group_t *G, char *name);

extern const qpms_finite_group_t QPMS_FINITE_GROUP_TRIVIAL;
extern const qpms_finite_group_t QPMS_FINITE_GROUP_TRIVIAL_G;

#endif // QPMS_GROUPS_H
