/********************************************************************/
/*  Module        : Parsing supplementary routines                  */
/*                                                                  */
/*  Version       : 2.9                                             */
/*  Last revision : 05/12/94 14:55:46                               */
/*                                                                  */
/*  Description :                                                   */
/*     Supplies routines needed during parsing.                     */
/*                                                                  */
/*  Functions supplied :                                            */
/*     -                                                            */
/*                                                                  */
/********************************************************************/

# include	<ctype.h>
# include	"aglobals.h"
# include	"fdecla.h"
# include	"parsesup.h"
# include	"grpring.h"
# include	"storage.h"
# include	"aut.h"
# include "error.h"

typedef struct action {
	TYPE type;
	void (*(*rout)(void*,void*));
} ACTION;

extern int cut, fend, prime;
extern PCGRPDESC *group_desc;
extern int bperelem;
extern FILE *out_hdl;
extern DSTYLE displaystyle;

VEC gr_invers				_(( VEC elem, int mod_id ));
void copy_list 			_(( LISTP *src, LISTP *dest, int perm ));
void show_aggrpdesc			_(( AGGRPDESC *g ));
void pcgroup_to_code 		_(( PCGRPDESC *g, int bracket ));
PCGRPDESC *code_to_pcgroup	_(( DYNLIST p ));
void write_intlist 			_(( int value, int is_start, int is_end ));
HOM *code_to_hom 			_(( DYNLIST p ));
void hom_to_code 			_(( HOM *a ));

OPTION display_basis = STANDARD_BASIS;
static ACTION ***act_table;

void init_act_table ( void )
{
	int i, j, k;
	
	/* create empty table */
	act_table = ARRAY ( MAXOPERANDS, ACTION** );
	for ( i = 0; i < MAXOPERANDS; i++ ) {
		act_table[i] = ARRAY ( MAXTYPES, ACTION* );
		for ( j = 0; j < MAXTYPES; j++ ) {
			act_table[i][j] = ARRAY ( MAXTYPES, ACTION );
			for ( k = 0; k < MAXTYPES; k++ ) {
				act_table[i][j][k].type = NOTYPE;
				act_table[i][j][k].rout = NULL;
			}
		}
	}
	
	/* initialize */
	act_table[O_ADD][INT][INT].type = INT;
	act_table[O_ADD][INT][INT].rout = g_add_int;
	act_table[O_ADD][INT][GRELEMENT].type = GRELEMENT;
	act_table[O_ADD][INT][GRELEMENT].rout = g_s_adda_gre;
	act_table[O_ADD][GRELEMENT][INT].type = GRELEMENT;
	act_table[O_ADD][GRELEMENT][INT].rout = g_s_addb_gre;
	act_table[O_ADD][GRELEMENT][GRELEMENT].type = GRELEMENT;
	act_table[O_ADD][GRELEMENT][GRELEMENT].rout = g_add_gre;
	act_table[O_ADD][VECTORSPACE][VECTORSPACE].type = VECTORSPACE;
	act_table[O_ADD][VECTORSPACE][VECTORSPACE].rout = g_add_vs;

	act_table[O_SUB][INT][INT].type = INT;
	act_table[O_SUB][INT][INT].rout = g_sub_int;
	act_table[O_SUB][INT][GRELEMENT].type = GRELEMENT;
	act_table[O_SUB][INT][GRELEMENT].rout = g_s_suba_gre;
	act_table[O_SUB][GRELEMENT][INT].type = GRELEMENT;
	act_table[O_SUB][GRELEMENT][INT].rout = g_s_subb_gre;
	act_table[O_SUB][GRELEMENT][GRELEMENT].type = GRELEMENT;
	act_table[O_SUB][GRELEMENT][GRELEMENT].rout = g_sub_gre;

	act_table[O_MUL][INT][INT].type = INT;
	act_table[O_MUL][INT][INT].rout = g_mul_int;
	act_table[O_MUL][INT][GRELEMENT].type = GRELEMENT;
	act_table[O_MUL][INT][GRELEMENT].rout = g_s_mula_gre;
	act_table[O_MUL][GRELEMENT][INT].type = GRELEMENT;
	act_table[O_MUL][GRELEMENT][INT].rout = g_s_mulb_gre;
	act_table[O_MUL][GRELEMENT][GRELEMENT].type = GRELEMENT;
	act_table[O_MUL][GRELEMENT][GRELEMENT].rout = g_mul_gre;
	act_table[O_MUL][VECTORSPACE][VECTORSPACE].type = VECTORSPACE;
	act_table[O_MUL][VECTORSPACE][VECTORSPACE].rout = g_mul_vs;
	act_table[O_MUL][GROUPEL][GROUPEL].type = GROUPEL;
	act_table[O_MUL][GROUPEL][GROUPEL].rout = g_mul_gel;

	act_table[O_DIV][INT][INT].type = INT;
	act_table[O_DIV][INT][INT].rout = g_div_int;
	act_table[O_DIV][INT][GRELEMENT].type = GRELEMENT;
	act_table[O_DIV][INT][GRELEMENT].rout = g_s_diva_gre;
	act_table[O_DIV][GRELEMENT][INT].type = GRELEMENT;
	act_table[O_DIV][GRELEMENT][INT].rout = g_s_divb_gre;
	act_table[O_DIV][GRELEMENT][GRELEMENT].type = GRELEMENT;
	act_table[O_DIV][GRELEMENT][GRELEMENT].rout = g_div_gre;

	act_table[O_UMI][INT][INT].type = INT;
	act_table[O_UMI][INT][INT].rout = g_umi_int;
	act_table[O_UMI][GRELEMENT][INT].type = GRELEMENT;
	act_table[O_UMI][GRELEMENT][INT].rout = g_umi_gre;
	
	act_table[O_EXP][INT][INT].type = INT;
	act_table[O_EXP][INT][INT].rout = g_exp_int;
	act_table[O_EXP][GRELEMENT][INT].type = GRELEMENT;
	act_table[O_EXP][GRELEMENT][INT].rout = g_exp_gre;
	act_table[O_EXP][VECTORSPACE][INT].type = VECTORSPACE;
	act_table[O_EXP][VECTORSPACE][INT].rout = g_exp_vs;
	act_table[O_EXP][GROUPEL][INT].type = GROUPEL;
	act_table[O_EXP][GROUPEL][INT].rout = g_exp_gel;

	act_table[O_LIE][INT][INT].type = INT;
	act_table[O_LIE][INT][INT].rout = g_lie_int;
	act_table[O_LIE][INT][GRELEMENT].type = GRELEMENT;
	act_table[O_LIE][INT][GRELEMENT].rout = g_s_lie_gre;
	act_table[O_LIE][GRELEMENT][INT].type = GRELEMENT;
	act_table[O_LIE][GRELEMENT][INT].rout = g_s_lie_gre;
	act_table[O_LIE][GRELEMENT][GRELEMENT].type = GRELEMENT;
	act_table[O_LIE][GRELEMENT][GRELEMENT].rout = g_lie_gre;
	act_table[O_LIE][VECTORSPACE][VECTORSPACE].type = VECTORSPACE;
	act_table[O_LIE][VECTORSPACE][VECTORSPACE].rout = g_lie_vs;
	
}

int findcgen ( char *name, int len )
{
	char *new_name = ALLOCATE ( len+1 );
	int i;
	
	if ( group_desc != NULL ) {
		strncpy ( new_name, name, len );
		new_name[len] = '\0';
		for ( i = 0; i < len; i++ )
			if ( isupper ( new_name[i] ) )
				new_name[i] = tolower ( new_name[i] );
	
		for ( i = 0; i < group_desc->num_gen; i++ )
			if ( !strcmp ( group_desc->gen[i], new_name ) )
				return ( i );
	}
	return ( -1 );
}

void *g_mul_gre ( void *el1, void *el2 )
{
	return (void *)GROUP_MUL ( (VEC)el1, (VEC)el2, cut );
}

void *g_exp_gre ( void *el1, void *el2 )
{
	int *pot = (int *)el2;
	VEC res;
	
	if ( *pot < 0 ) {
		res = group_exp ( (VEC)el1, -*pot, cut );
		res = gr_invers ( res, cut );
	}
	else 
		res = group_exp ( (VEC)el1, *pot, cut );
	return (void *)res;
}

void *g_add_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	
	copy_vector ( (VEC)el2, res, fend );
	ADD_VECTOR ( (VEC)el1, res, fend );
	return (void *)res;
}

void *g_sub_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	
	copy_vector ( (VEC)el2, res, fend );
	SUBA_VECTOR ( (VEC)el1, res, fend );
	return (void *)res;
}

void *g_div_gre ( void *el1, void *el2 )
{
	VEC help = (VEC)el2;
	
	help = gr_invers ( help, cut );
	if ( help == NULL )
		return ( NULL );
	return (void *)GROUP_MUL ( (VEC)el1, help, cut );
}

void *g_umi_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	
	copy_vector ( (VEC)el1, res, fend );
	SMUL_VECTOR ( prime-1, res, fend );
	return (void *)res;
}

void *g_lie_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	VEC help;
	
	help = GROUP_MUL ( (VEC)el1, (VEC)el2, cut );
	copy_vector ( help, res, fend );
	help = GROUP_MUL ( (VEC)el2, (VEC)el1, cut );
	SUBB_VECTOR ( help, res, fend );
	return (void *)res;
}

void *g_s_mula_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	int *val = (int *)el1;
	
	copy_vector ( (VEC)el2, res, fend );
	SMUL_VECTOR ( (*val) % prime, res, fend );
	return (void *)res;
}

void *g_s_mulb_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	int *val = (int *)el2;
	
	copy_vector ( (VEC)el1, res, fend );
	SMUL_VECTOR ( (*val) % prime, res, fend );
	return (void *)res;
}

void *g_s_diva_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	int *val = (int *)el1;
	
	copy_vector ( (VEC)el2, res, fend );
	*val = fp_inv ( (*val) % prime );
	SMUL_VECTOR ( *val, res, fend );
	return (void *)res;
}

void *g_s_divb_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	int *val = (int *)el2;
	
	copy_vector ( (VEC)el1, res, fend );
	*val = fp_inv ( (*val) % prime );
	SMUL_VECTOR ( *val, res, fend );
	return (void *)res;
}

void *g_s_adda_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	int *val = (int *)el1;
	
	copy_vector ( (VEC)el2, res, fend );
	res[0] = fp_add ( res[0], (*val) % prime );
	return (void *)res;
}

void *g_s_addb_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	int *val = (int *)el2;
	
	copy_vector ( (VEC)el1, res, fend );
	res[0] = fp_add ( res[0], (*val) % prime );
	return (void *)res;
}

void *g_s_suba_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	int *val = (int *)el1;
	
	copy_vector ( (VEC)el2, res, fend );
	SMUL_VECTOR ( prime-1, res, fend );
	res[0] = fp_add ( res[0], (*val) % prime );
	return (void *)res;
}

void *g_s_subb_gre ( void *el1, void *el2 )
{
	VEC res = ALLOCATE ( fend );
	int *val = (int *)el2;
	
	copy_vector ( (VEC)el1, res, fend );
	*val = *val % prime;
	res[0] = fp_add ( res[0], prime - (*val) );
	return (void *)res;
}

void *g_s_lie_gre ( void *el1, void *el2 )
{
	return (void *)CALLOCATE ( fend );
}

void *g_mul_gel ( void *el1, void *el2 )
{
	return (void *)monom_mul ( (PCELEM)el1, (PCELEM)el2 );
}

void *g_exp_gel ( void *el1, void *el2 )
{
	int *pot = (int *)el2;
	PCELEM res;
	
	if ( *pot < 0 ) {
		res = g_expo ( (PCELEM)el1, -*pot );
		res = g_invers ( res );
	}
	else 
		res = g_expo ( (PCELEM)el1, *pot );
	return (void *)res;
}

void *g_mul_int ( void *el1, void *el2 )
{
	int *res = ALLOCATE ( sizeof ( int ) );
	int *v1 = (int *)el1;
	int *v2 = (int *)el2;
	
	*res = (*v1)*(*v2);
	return (void *)res;
}

void *g_exp_int ( void *el1, void *el2 )
{
	int *res = ALLOCATE ( sizeof ( int ) );
	int *v1 = (int *)el1;
	int *v2 = (int *)el2;
	int pow = (*v2) > 0 ? *v2 : -(*v2);
	int i;
	
	*res = 1;
	for ( i = 0; i < pow; i++ )
		*res *= (*v1);
	if ( (*v2) < 0 ) {
		if ( (*res) == 0 ) {
			set_error ( DIVISION_BY_ZERO );
			return ( NULL );
		}
		*res = 1 / (*res);
	}
	return (void *)res;
}

void *g_add_int ( void *el1, void *el2 )
{
	int *res = ALLOCATE ( sizeof ( int ) );
	int *v1 = (int *)el1;
	int *v2 = (int *)el2;
	
	*res = (*v1)+(*v2);
	return (void *)res;
}

void *g_sub_int ( void *el1, void *el2 )
{
	int *res = ALLOCATE ( sizeof ( int ) );
	int *v1 = (int *)el1;
	int *v2 = (int *)el2;
	
	*res = (*v1)-(*v2);
	return (void *)res;
}

void *g_div_int ( void *el1, void *el2 )
{
	int *res = ALLOCATE ( sizeof ( int ) );
	int *v1 = (int *)el1;
	int *v2 = (int *)el2;
	
	if ( (*v2) == 0 ) {
		set_error ( DIVISION_BY_ZERO );
		return NULL;
	}
	*res = (*v1)/(*v2);
	return (void *)res;
}


void *g_umi_int ( void *el1, void *el2 )
{
	int *res = ALLOCATE ( sizeof ( int ) );
	int *v1 = (int *)el1;
	
	*res = -(*v1);
	return (void *)res;
}

void *g_lie_int ( void *el1, void *el2 )
{
	return (void *)CALLOCATE ( sizeof ( int ) );
}

void *g_mul_vs ( void *el1, void *el2 )
{
	return (void *)meet_space ( (SPACE *)el1, (SPACE *)el2 );
}

void *g_add_vs ( void *el1, void *el2 )
{
	return (void *)join_space ( (SPACE *)el1, (SPACE *)el2 );
}

void *g_exp_vs ( void *el1, void *el2 )
{
	return NULL;
}

void *g_lie_vs ( void *el1, void *el2 )
{
	return (void *)s_lie_prod ( (SPACE *)el1, (SPACE *)el2 );
}

GENVAL *galloc ( TYPE of_type )
{
	GENVAL *newexpr;
	
	newexpr = (GENVAL *)tallocate ( sizeof ( GENVAL ) );
	
	switch ( newexpr->exptype = of_type ) {
		case INT :
				newexpr->pval = tcallocate ( sizeof(int) );
				break;
		case GROUP :
				newexpr->pval = tcallocate ( sizeof(GRPDSC) );
				break;
		case PCGROUP :
				newexpr->pval = tcallocate ( sizeof(PCGRPDESC) );
				break;
		case AGGROUP :
				newexpr->pval = tcallocate ( sizeof(AGGRPDESC) );
				break;
		case GROUPRING:
				newexpr->pval = tcallocate ( sizeof(GRPRING) );
				break;
		case GRELEMENT:
				newexpr->pval = tcallocate ( fend );
				break;
		case GROUPEL:
				newexpr->pval = tcallocate ( bperelem );
				break;
		case VECTORSPACE:
				newexpr->pval = tcallocate ( sizeof(SPACE) );
				break;
		case DLIST:
				newexpr->pval = tcallocate ( sizeof(LISTP) );
				break;
		case HOMREC:
				newexpr->pval = tcallocate ( sizeof(HOM) );
				break;
		case NOTYPE :
				newexpr->pval = NULL;
	}
	return ( newexpr );
}

GENVAL *gpermalloc ( TYPE of_type )
{
	GENVAL *newexpr;
	
	newexpr = (GENVAL *)allocate ( sizeof ( GENVAL ) );
	
	switch ( newexpr->exptype = of_type ) {
		case INT :
				newexpr->pval = callocate ( sizeof(int) );
				break;
		case GROUP :
				newexpr->pval = callocate ( sizeof(GRPDSC) );
				break;
		case PCGROUP :
				newexpr->pval = callocate ( sizeof(PCGRPDESC) );
				break;
		case AGGROUP :
				newexpr->pval = callocate ( sizeof(AGGRPDESC) );
				break;
		case GROUPRING:
				newexpr->pval = callocate ( sizeof(GRPRING) );
				break;
		case GRELEMENT:
				newexpr->pval = callocate ( fend );
				break;
		case GROUPEL:
				newexpr->pval = callocate ( bperelem );
				break;
		case VECTORSPACE :
				newexpr->pval = callocate ( sizeof(SPACE) );
				break;
		case DLIST:
				newexpr->pval = callocate ( sizeof(LISTP) );
				break;
		case HOMREC:
				newexpr->pval = callocate ( sizeof(HOM) );
				break;
		case NOTYPE :
				newexpr->pval = NULL;
	}
	return ( newexpr );
}


GENVAL *do_op ( GENVAL *expr1, GENVAL *expr2, OPTYPE operand )
{
	GENVAL *rexpr;
	TYPE ctype, op2type;

	if ( expr2 == NULL )
		op2type = INT;
	else
		op2type = expr2->exptype;
	if ( (ctype = act_table[operand][expr1->exptype][op2type].type) != NOTYPE ) {
		rexpr = tallocate ( sizeof ( GENVAL ) );
		rexpr->exptype = ctype;
		rexpr->pval = (*act_table[operand][expr1->exptype][op2type].rout)
			( expr1->pval, (expr2 == NULL) ? NULL : expr2->pval );
		return ( (rexpr->pval == NULL) ? NULL : rexpr  );
	}
	return ( NULL );
}

GENVAL *code_to_expr ( LISTP* intlist )
{
	GENVAL *rexpr;
	DYNLIST p;
	
	if ( intlist == NULL )
		return ( NULL );
	
	p = intlist->first;
	rexpr = tallocate ( sizeof ( GENVAL ) );
	rexpr->exptype = p->value.intv;
	switch ( rexpr->exptype ) {
		case PCGROUP:
			rexpr->pval = code_to_pcgroup ( p->next );
			break;
		case HOMREC:
			rexpr->pval = code_to_hom ( p->next );
			break;
		default:
			set_error ( WRONG_TYPE );
	}
	return ( rexpr );
}

void expr_to_code ( GENVAL *expr )
{
	switch ( expr->exptype ) {
		case PCGROUP:
			pcgroup_to_code ( (PCGRPDESC *)expr->pval, TRUE );
			break;
		case HOMREC:
			hom_to_code ( (HOM *)expr->pval );
			break;
		default:
			set_error ( WRONG_TYPE );
	}
}

void assign_symbol ( symbol *sym, GENVAL *expr )
{
	sym->type = expr->exptype;
	sym->object = gpermalloc ( expr->exptype );

	switch ( expr->exptype ) {
		case INT:
			*((int *)sym->object) = *((int *)expr->pval);
			break;
		case GROUP:
			copy_group ( (GRPDSC *)expr->pval, (GRPDSC *)sym->object, TRUE );
			strncpy ( ((GRPDSC *)sym->object)->group_name, sym->name, NAME_MAX+1 );
			break;
		case PCGROUP:
			copy_pcgroup ( (PCGRPDESC *)expr->pval, (PCGRPDESC *)sym->object, TRUE, NULL );
			strncpy ( ((PCGRPDESC *)sym->object)->group_name, sym->name, NAME_MAX+1 );
			break;
		case AGGROUP:
			copy_aggroup ( (AGGRPDESC *)expr->pval, (AGGRPDESC *)sym->object, TRUE, NULL );
			strncpy ( ((AGGRPDESC *)sym->object)->group_name, sym->name, NAME_MAX+1 );
			break;
		case GROUPRING:
			copy_grpring ( (GRPRING *)expr->pval, (GRPRING *)sym->object, TRUE );
			break;
		case GRELEMENT:
			copy_vector ( (VEC)expr->pval, (VEC)sym->object, fend );			
			break;
		case GROUPEL:
			copy_vector ( (PCELEM)expr->pval, (PCELEM)sym->object, bperelem );			
			break;
		case VECTORSPACE:
			copy_space ( (SPACE *)expr->pval, (SPACE *)sym->object, TRUE );
			break;
		case DLIST:
			copy_list ( (LISTP *)expr->pval, (LISTP *)sym->object, TRUE );			
			break;
		case HOMREC:
			copy_hom ( (HOM *)expr->pval, (HOM *)sym->object, TRUE, NULL );			
			break;
		default:
			set_error ( WRONG_TYPE );
	}
}

void show_dlist ( LISTP *list )
{
	DYNLIST p;
	
	printf ( "[" );
	for ( p = list->first; p != NULL; p = p->next ) {
		printf ( "%d", p->value.intv );
		if ( p != list->last )
			printf ( "," );
	}
	printf ( "]\n" );
}

void print_expr ( GENVAL *expr )
{
	switch ( expr->exptype ) {
		case INT:
			printf ( "%d\n", *((int *)expr->pval) );
			break;
		case GROUP:
			show_grpdsc ( (GRPDSC *)expr->pval );
			break;
		case PCGROUP:
			show_pcgrpdesc ( (PCGRPDESC *)expr->pval );
			break;
		case AGGROUP:
			show_aggrpdesc ( (AGGRPDESC *)expr->pval );
			break;
		case GROUPRING:
			show_grpring ( (GRPRING *)expr->pval );
			break;
		case GRELEMENT:
			if ( display_basis == STANDARD_BASIS ) {
				PUSH_STACK();
				cgroup_write ( n_c_trans ( (VEC)expr->pval, cut ) );
				POP_STACK();
			}
			else
				n_group_write ( (VEC)expr->pval, cut );
			break;
		case GROUPEL:
			word_write ( (PCELEM)expr->pval );
			fprintf ( out_hdl, "\n" );
			break;
		case VECTORSPACE:
			show_space ( (SPACE *)expr->pval );
			break;
		case DLIST:
			show_dlist ( (LISTP *)expr->pval );
			break;
		case HOMREC:
			show_hom ( (HOM *)expr->pval, "" );
			break;
		default:
			set_error ( WRONG_TYPE );
	}
}

void copy_space ( SPACE *src, SPACE *dest, int perm )
{
	int i;
	
	dest->total_dim = src->total_dim;
	dest->dimension = src->dimension;
	dest->b_flag = src->b_flag;
	i = src->total_dim * src->dimension;
	if ( perm )
		dest->basis = allocate ( i );
	else
		dest->basis = tallocate ( i );
	copy_vector ( src->basis, dest->basis, i );
}

void copy_list ( LISTP *src, LISTP *dest, int perm )
{
	DYNLIST p, r;
	DYNLIST q = NULL;
	
	r = NULL;
	for ( p = src->first; p != NULL; p = p->next ) {
		if ( perm )
			q = allocate ( sizeof ( dynlistitem ) );
		else
			q = tallocate ( sizeof ( dynlistitem ) );
		q->value = p->value;
		if ( r == NULL )
			dest->first = r = q;
		else
			r->next = q;
	}
	dest->last = q;
}

node node_cpy ( node s, int perm )
{
	node d;
	
	if ( s == NULL ) 
		d = NULL;
	else {
		if ( perm )
			d = allocate ( sizeof ( rel_node ) );
		else
			d = tallocate ( sizeof ( rel_node ) );
		d->nodetype = s->nodetype;
		d->value = s->value;
		d->left = node_cpy ( s->left, perm );
		d->right = node_cpy ( s->right, perm ); 
	}
	return d;
}

void copy_group ( GRPDSC *src, GRPDSC *dest, int perm )
{
	int i;
	
	memcpy ( dest, src, sizeof ( GRPDSC ) );
	
	if ( perm ) {
		dest->rel_list = allocate ( dest->num_rel * sizeof ( node ) );
		dest->gen = allocate ( src->num_gen * sizeof ( char * ) );
		for ( i = 0; i < src->num_gen; i++ )
			dest->gen[i] = allocate ( strlen ( src->gen[i] )+1 );
		if ( src->pc_pres != NULL )
			dest->pc_pres = allocate ( sizeof ( PCGRPDESC ) );
		if ( src->isog != NULL )
			dest->isog = allocate ( sizeof ( HOM ) );
	}
	else {
		dest->rel_list = tallocate ( dest->num_rel * sizeof ( node ) );
		dest->gen = tallocate ( src->num_gen * sizeof ( char * ) );
		for ( i = 0; i < src->num_gen; i++ )
			dest->gen[i] = tallocate ( strlen ( src->gen[i] )+1 );
		if ( src->pc_pres != NULL )
			dest->pc_pres = tallocate ( sizeof ( PCGRPDESC ) );
		if ( src->isog != NULL )
			dest->isog = tallocate ( sizeof ( HOM ) );
	}
	for ( i = 0; i < dest->num_rel; i++ )
		dest->rel_list[i] = node_cpy ( src->rel_list[i], perm );
	for ( i = 0; i < src->num_gen; i++ )
		strcpy ( dest->gen[i], src->gen[i] );
	if ( src->pc_pres != NULL )
		copy_pcgroup ( src->pc_pres, dest->pc_pres, perm, NULL );
	if ( src->isog != NULL )
		if ( dest->pc_pres != NULL )
			copy_hom ( src->isog, dest->isog, perm, dest->pc_pres );
		else	
			copy_hom ( src->isog, dest->isog, perm, NULL );
}

void copy_pcgroup ( PCGRPDESC *src, PCGRPDESC *dest, int perm, HOM *autos )
{
	int i, cnr;

	memcpy ( dest, src, sizeof ( PCGRPDESC ) );
	
	cnr = ( src->num_gen * ( src->num_gen -1 ) ) >> 1;
	if ( perm ) {
		dest->gen = allocate ( src->num_gen * sizeof ( char * ) );
		dest->g_max = callocate ( src->num_gen * sizeof ( int ) );
		dest->g_ideal = callocate ( src->num_gen * sizeof ( int ) );
		dest->image = callocate ( src->num_gen * sizeof ( int ) );
		dest->pimage = callocate ( src->num_gen * sizeof ( int ) );
		dest->nom = callocate ( src->num_gen * sizeof ( PCELEM ) );
		dest->p_list = (ge_pair **)allocate ( src->num_gen * sizeof ( ge_pair *) );
		dest->p_len = (int *)allocate ( src->num_gen * sizeof ( int ) );
		dest->c_list = (ge_pair **)allocate ( cnr * sizeof ( ge_pair * ) );
		dest->c_len = (int *)allocate ( cnr * sizeof ( int ) );
		dest->pc_weight = allocate ( src->num_gen * sizeof ( int ) );
		dest->exp_p_lcs = allocate ( (src->exp_p_class+1) * sizeof ( FILT ) );
		dest->def_list = allocate ( src->num_gen * sizeof ( node ) );
		for ( i = 0; i < src->num_gen; i++ )
			dest->gen[i] = allocate ( strlen ( src->gen[i] )+1 );
	}
	else {
		dest->gen = tcallocate ( src->num_gen * sizeof ( char * ) );
		dest->g_max = tcallocate ( src->num_gen * sizeof ( int ) );
		dest->g_ideal = tcallocate ( src->num_gen * sizeof ( int ) );
		dest->image = tcallocate ( src->num_gen * sizeof ( int ) );
		dest->pimage = tcallocate ( src->num_gen * sizeof ( int ) );
		dest->nom = tcallocate ( src->num_gen * sizeof ( PCELEM ) );
		dest->p_list = (ge_pair **)tallocate ( src->num_gen * sizeof ( ge_pair *) );
		dest->p_len = (int *)tallocate ( src->num_gen * sizeof ( int ) );
		dest->c_list = (ge_pair **)tallocate ( cnr * sizeof ( ge_pair * ) );
		dest->c_len = (int *)tallocate ( cnr * sizeof ( int ) );
		dest->pc_weight = tallocate ( src->num_gen * sizeof ( int ) );
		dest->exp_p_lcs = tallocate ( (src->exp_p_class+1) * sizeof ( FILT ) );
		dest->def_list = tallocate ( src->num_gen * sizeof ( node ) );
		for ( i = 0; i < src->num_gen; i++ )
			dest->gen[i] = tallocate ( strlen ( src->gen[i] )+1 );
	}

	for ( i = 0; i < src->num_gen; i++ )
		dest->def_list[i] = node_cpy ( src->def_list[i], perm );

	/* zero_vector ( dest->group_name, 50 ); */
	for ( i = 0; i < src->num_gen; i++ )
		strcpy ( dest->gen[i], src->gen[i] );

	memcpy ( dest->g_max, src->g_max, src->num_gen * sizeof ( int ) );
	memcpy ( dest->g_ideal, src->g_ideal, src->num_gen * sizeof ( int ) );
	memcpy ( dest->image, src->image, src->num_gen * sizeof ( int ) );
	memcpy ( dest->pimage, src->pimage, src->num_gen * sizeof ( int ) );
	memcpy ( dest->p_len, src->p_len, src->num_gen * sizeof ( int ) );
	memcpy ( dest->c_len, src->c_len, cnr * sizeof ( int ) );
	memcpy ( dest->pc_weight, src->pc_weight, src->num_gen * sizeof ( int ) );
	memcpy ( dest->exp_p_lcs, src->exp_p_lcs, (src->exp_p_class+1) * sizeof ( FILT ) );

	for ( i = 0; i < dest->num_gen; i++ ) {
		if ( src->p_list[i] == NULL )
			dest->p_list[i] = NULL;
		else {
			if ( perm )
				dest->p_list[i] = allocate ( (dest->p_len[i]+1) * sizeof ( ge_pair ) );
			else
				dest->p_list[i] = tallocate ( (dest->p_len[i]+1) * sizeof ( ge_pair ) );
			memcpy ( dest->p_list[i], src->p_list[i], (dest->p_len[i]+1) * sizeof ( ge_pair ) );
		}
	}
	for ( i = 0; i < cnr; i++ ) {
		if ( src->c_list[i] == NULL )
			dest->c_list[i] = NULL;
		else {
			if ( perm )
				dest->c_list[i] = allocate ( (dest->c_len[i]+1) * sizeof ( ge_pair ) );
			else
				dest->c_list[i] = tallocate ( (dest->c_len[i]+1) * sizeof ( ge_pair ) );
			memcpy ( dest->c_list[i], src->c_list[i], (dest->c_len[i]+1) * sizeof ( ge_pair ) );
		}
	}
	for ( i = 0; i < dest->num_gen; i++ ) {
		if ( perm )
			dest->nom[i] = allocate ( dest->num_gen );
		else
			dest->nom[i] = tallocate ( dest->num_gen );
		memcpy ( dest->nom[i], src->nom[i], dest->num_gen );
	}
	if ( src->autg != NULL ) {
		if ( autos != NULL )
			dest->autg = autos;
		else {
			if ( perm ) 
				dest->autg = allocate ( sizeof ( HOM ) );
			else
				dest->autg = tallocate ( sizeof ( HOM ) );
			copy_hom ( src->autg, dest->autg, perm, dest );
		}
	}
}

int gep_len ( ge_pair *gep )
{
	int i;
	
	for ( i = 0; ;i++ )
		if ( gep[i].g == -1 )
			break;
	return ( i+1 );
}	
	
void copy_aggroup ( AGGRPDESC *src, AGGRPDESC *dest, int perm, HOM *autos )
{
	int i, cnr, len;

	memcpy ( dest, src, sizeof ( AGGRPDESC ) );
	
	cnr = ( src->num_gen * ( src->num_gen -1 ) ) >> 1;
	if ( perm ) {
		dest->gen = allocate ( src->num_gen * sizeof ( char * ) );
		dest->powers = callocate ( src->num_gen * sizeof ( int ) );
		dest->nom = callocate ( src->num_gen * sizeof ( PCELEM ) );
		dest->p_list = (ge_pair **)allocate ( src->num_gen * sizeof ( ge_pair *) );
		dest->p_len = (int *)allocate ( src->num_gen * sizeof ( int ) );
		dest->c_list = (ge_pair **)allocate ( cnr * sizeof ( ge_pair * ) );
		dest->c_len = (int *)allocate ( cnr * sizeof ( int ) );
		dest->conjugates = allocate ( cnr * sizeof ( ge_pair * ) );
		dest->avec = allocate ( src->num_gen * sizeof ( int ) );
		dest->elab_series = allocate ( (src->elab_length+1) * sizeof ( FILT ) );
		dest->def_list = allocate ( src->num_gen * sizeof ( GENDEF ) );
		for ( i = 0; i < src->num_gen; i++ )
			dest->gen[i] = allocate ( strlen ( src->gen[i] ) );
		if ( src->autg != NULL )
			dest->autg = allocate ( sizeof ( HOM ) );
	}
	else {
		dest->gen = tcallocate ( src->num_gen * sizeof ( char * ) );
		dest->powers = tcallocate ( src->num_gen * sizeof ( int ) );
		dest->nom = tcallocate ( src->num_gen * sizeof ( PCELEM ) );
		dest->p_list = (ge_pair **)tallocate ( src->num_gen * sizeof ( ge_pair *) );
		dest->p_len = (int *)tallocate ( src->num_gen * sizeof ( int ) );
		dest->c_list = (ge_pair **)tallocate ( cnr * sizeof ( ge_pair * ) );
		dest->c_len = (int *)tallocate ( cnr * sizeof ( int ) );
		dest->conjugates = tallocate ( cnr * sizeof ( ge_pair * ) );
		dest->avec = tallocate ( src->num_gen * sizeof ( int ) );
		dest->elab_series = tallocate ( (src->elab_length+1) * sizeof ( FILT ) );
		dest->def_list = tallocate ( src->num_gen * sizeof ( GENDEF ) );
		for ( i = 0; i < src->num_gen; i++ )
			dest->gen[i] = tallocate ( strlen ( src->gen[i] ) );
		if ( src->autg != NULL )
			dest->autg = tallocate ( sizeof ( HOM ) );
	}
	
	for ( i = 0; i < src->num_gen; i++ )
		strcpy ( dest->gen[i], src->gen[i] );

	memcpy ( dest->powers, src->powers, src->num_gen * sizeof ( int ) );
	memcpy ( dest->p_len, src->p_len, src->num_gen * sizeof ( int ) );
	memcpy ( dest->c_len, src->c_len, cnr * sizeof ( int ) );
	memcpy ( dest->avec, src->avec, src->num_gen * sizeof ( int ) );
	memcpy ( dest->elab_series, src->elab_series, (src->elab_length+1) * sizeof ( FILT ) );
	memcpy ( dest->def_list, src->def_list, src->num_gen * sizeof ( GENDEF ) );

	for ( i = 0; i < dest->num_gen; i++ ) {
		if ( src->p_list[i] == NULL )
			dest->p_list[i] = NULL;
		else {
			if ( perm )
				dest->p_list[i] = allocate ( (dest->p_len[i]+1) * sizeof ( ge_pair ) );
			else
				dest->p_list[i] = tallocate ( (dest->p_len[i]+1) * sizeof ( ge_pair ) );
			memcpy ( dest->p_list[i], src->p_list[i], (dest->p_len[i]+1) * sizeof ( ge_pair ) );
		}
	}
	for ( i = 0; i < cnr; i++ ) {
		if ( src->c_list[i] == NULL )
			dest->c_list[i] = NULL;
		else {
			if ( perm )
				dest->c_list[i] = allocate ( (dest->c_len[i]+1) * sizeof ( ge_pair ) );
			else
				dest->c_list[i] = tallocate ( (dest->c_len[i]+1) * sizeof ( ge_pair ) );
			memcpy ( dest->c_list[i], src->c_list[i], (dest->c_len[i]+1) * sizeof ( ge_pair ) );
		}

		len = gep_len ( src->conjugates[i] );
		if ( perm )
			dest->conjugates[i] = allocate ( len * sizeof ( ge_pair ) );
		else
			dest->conjugates[i] = tallocate ( len * sizeof ( ge_pair ) );
		memcpy ( dest->conjugates[i], src->conjugates[i], len * sizeof ( ge_pair ) );
	}
	for ( i = 0; i < dest->num_gen; i++ ) {
		if ( perm )
			dest->nom[i] = allocate ( dest->num_gen );
		else
			dest->nom[i] = tallocate ( dest->num_gen );
		memcpy ( dest->nom[i], src->nom[i], dest->num_gen );
	}
	if ( autos != NULL )
		printf ( "automorphisms found !\n" );
	dest->autg = NULL;
}

void copy_grpring ( GRPRING *src, GRPRING *dest, int perm )
{
	int i;

	memcpy ( dest, src, sizeof ( GRPRING ) );
	
	
	if ( perm ) {
		dest->filtration = allocate ( (src->g->max_id + 1) * sizeof ( FILT ) );
		dest->c_monom = allocate ( src->g->group_card * sizeof ( PCELEM ) );
		dest->n_monom = allocate ( src->g->group_card * sizeof ( VEC ) );
		dest->ngen_vec = allocate ( src->g->num_gen * sizeof ( VEC ) );
		dest->el_num = allocate ( src->g->group_card * sizeof ( int ) );
		for ( i = 0; i < src->g->group_card; i++ ) {
			dest->c_monom[i] = allocate ( src->g->num_gen );
			dest->n_monom[i] = allocate ( src->g->num_gen );
		}
		for ( i = 0; i  < src->g->num_gen; i++ ) 
			dest->ngen_vec[i] = callocate ( src->g->group_card );
		dest->g = allocate ( sizeof ( PCGRPDESC ) );
	}
	else {
		dest->filtration = tallocate ( (src->g->max_id + 1) * sizeof ( FILT ) );
		dest->c_monom = tallocate ( src->g->group_card * sizeof ( PCELEM ) );
		dest->n_monom = tallocate ( src->g->group_card * sizeof ( VEC ) );
		dest->ngen_vec = tallocate ( src->g->num_gen * sizeof ( VEC ) );
		dest->el_num = tallocate ( src->g->group_card * sizeof ( int ) );
		for ( i = 0; i < src->g->group_card; i++ ) {
			dest->c_monom[i] = tallocate ( src->g->num_gen );
			dest->n_monom[i] = tallocate ( src->g->num_gen );
		}
		for ( i = 0; i  < src->g->num_gen; i++ ) 
			dest->ngen_vec[i] = tcallocate ( src->g->group_card );
		dest->g = tallocate ( sizeof ( PCGRPDESC ) );
	}
	
	memcpy ( dest->filtration, src->filtration, (src->g->max_id + 1) * sizeof ( FILT ) );
	memcpy ( dest->el_num, src->el_num, src->g->group_card * sizeof ( int ) );
	copy_pcgroup ( src->g, dest->g, perm, NULL );
	for ( i = 0; i < src->g->group_card; i++ ) {
		memcpy ( dest->c_monom[i], src->c_monom[i], src->g->num_gen );
		memcpy ( dest->n_monom[i], src->n_monom[i], src->g->num_gen );
	}
	for ( i = 0; i  < dest->g->num_gen; i++ ) 
		memcpy ( dest->ngen_vec[i], src->ngen_vec[i], src->g->group_card );

	dest->mul_table = src->mul_table;
	dest->jenn_table = src->jenn_table;
}

void copy_hom ( HOM *src, HOM *dest, int perm, PCGRPDESC *g )
{
	int i, j;
	int numgen;
	int hgens;
	
	memcpy ( dest, src, sizeof ( HOM ) );
	if ( src->auts == 0 && !src->elements )
		return;
	
	if ( g != NULL )
		dest->g = g;
	else {
		if ( perm )
			dest->g = allocate ( sizeof ( PCGRPDESC ) );
		else
			dest->g = tallocate ( sizeof ( PCGRPDESC ) );
		copy_pcgroup ( src->g, dest->g, perm, dest );
	}
	
	numgen = src->g->defs ? src->g->min_gen : src->g->num_gen;
	hgens = src->h == NULL ? numgen : src->h->num_gen;
	if ( perm ) {
		dest->aut_gens_dim = allocate ( (src->g->exp_p_class+1) * sizeof ( int ) );
		dest->out_gens_dim = allocate ( (src->g->exp_p_class+1) * sizeof ( int ) );
		dest->aut_gens = allocate ( (src->g->exp_p_class+1) * sizeof ( VEC* ) );
		if ( src->epimorphism != NULL )
			dest->epimorphism = allocate ( hgens * src->g->num_gen );
		for ( i = 1; i <= src->g->exp_p_class; i++ ) {
			dest->aut_gens[i] = allocate ( src->aut_gens_dim[i] * sizeof ( VEC ) );
			for ( j = 0; j < src->aut_gens_dim[i]; j++ )
				dest->aut_gens[i][j] = allocate ( src->g->num_gen * numgen );
		}
		if ( src->stabs != NULL ) {
			dest->stabs = allocate ( (src->g->max_id+1) * sizeof ( int* ) );
			for ( i = src->g->max_id; i > 1; i-- )
				dest->stabs[i] = callocate ( (src->aut_gens_dim[1]+1)*sizeof ( int ) );
		}
	}
	else {
		dest->aut_gens_dim = tallocate ( (src->g->exp_p_class+1) * sizeof ( int ) );
		dest->out_gens_dim = tallocate ( (src->g->exp_p_class+1) * sizeof ( int ) );
		dest->aut_gens = tallocate ( (src->g->exp_p_class+1) * sizeof ( VEC* ) );
		if ( src->epimorphism != NULL )
			dest->epimorphism = tallocate ( hgens * src->g->num_gen );
		for ( i = 1; i <= src->g->exp_p_class; i++ ) {
			dest->aut_gens[i] = tallocate ( src->aut_gens_dim[i] * sizeof ( VEC ) );
			for ( j = 0; j < src->aut_gens_dim[i]; j++ )
				dest->aut_gens[i][j] = tallocate ( src->g->num_gen * numgen);
		}	
		if ( src->stabs != NULL ) {
			dest->stabs = tallocate ( (src->g->max_id+1) * sizeof ( int* ) );
			for ( i = src->g->max_id; i > 1; i-- ) 
				dest->stabs[i] = tcallocate ( (src->aut_gens_dim[1]+1)*sizeof ( int ) );
		}
	}
	memcpy ( dest->aut_gens_dim, src->aut_gens_dim, (src->g->exp_p_class+1) * sizeof ( int ) );
	memcpy ( dest->out_gens_dim, src->out_gens_dim, (src->g->exp_p_class+1) * sizeof ( int ) );
	if ( src->epimorphism != NULL )
		memcpy ( dest->epimorphism, src->epimorphism,  hgens * src->g->num_gen );

	for ( i = 1; i <= src->g->exp_p_class; i++ ) {
		for ( j = 0; j < src->aut_gens_dim[i]; j++ )
			memcpy ( dest->aut_gens[i][j], src->aut_gens[i][j], src->g->num_gen * numgen);
	}
	if ( src->stabs != NULL )
		for ( i = src->g->max_id; i > 1; i-- )
			memcpy ( dest->stabs[i], src->stabs[i], (src->aut_gens_dim[1]+1)*sizeof ( int ) );
}

static DYNLIST pp = NULL;

void write_intlist ( int value, int is_start, int is_end )
{
	static int count;
	
	if ( is_start ) {
		count = 0;
		return;
	}
	printf ( "%d", value );
	if ( !is_end )
		printf ( "," );
	if ( ++count == 12 ) {
		count = 0;
		printf ( "\n" );
	}
}
	
void node_to_code ( node p )
{
	if ( p == NULL )
		write_intlist ( -1, FALSE, FALSE );
	else {
		write_intlist ( p->nodetype, FALSE, FALSE );
		write_intlist ( p->value, FALSE, FALSE );
		node_to_code ( p->left );
		node_to_code ( p->right );
	}
}

node code_to_node ( void )
{
	node n;
	
	if ( pp->value.intv == -1 ) {
		pp = pp->next;
		return ( NULL );
	}
	n = ALLOCATE ( sizeof ( rel_node ) );
	n->nodetype = pp->value.intv; pp = pp->next;
	n->value = pp->value.intv; pp = pp->next;
	n->left = code_to_node();
	n->right = code_to_node();
	return ( n );
}

void pcgroup_to_code ( PCGRPDESC *g, int bracket )
{
	int i, j, cnr;
	size_t l;
	char *rec_prefx, *rec_postfx;

	if ( displaystyle == GAP ) {
		rec_prefx = "SISYPHOS.SISCODE :=  [";
		rec_postfx = "];\n";
	}
	else {
		rec_prefx = "[";
		rec_postfx = "]\n";
	}
	

	cnr = ( g->num_gen * ( g->num_gen -1 ) ) >> 1;

	if ( bracket ) {
		printf ( "%s%d,\n", rec_prefx, PCGROUP );
		write_intlist ( 0, TRUE, FALSE );
	}
	else
		printf ( "%d,\n", PCGROUP );
		
	write_intlist ( g->prime, FALSE, FALSE );
	write_intlist ( g->num_gen, FALSE, FALSE );
	write_intlist ( g->group_card, FALSE, FALSE );
	write_intlist ( g->max_id, FALSE, FALSE );
	write_intlist ( g->min_gen, FALSE, FALSE );
	write_intlist ( g->defs, FALSE, FALSE );
	for ( i = 0; i < 50; i++ )
		write_intlist ( g->group_name[i], FALSE, FALSE );

	for ( i = 0; i < g->num_gen; i++ )
		write_intlist ( g->g_max[i], FALSE, FALSE );
	for ( i = 0; i < g->num_gen; i++ )
		write_intlist ( g->g_ideal[i], FALSE, FALSE );
	for ( i = 0; i < g->num_gen; i++ )
		write_intlist ( g->image[i], FALSE, FALSE );
	for ( i = 0; i < g->num_gen; i++ )
		write_intlist ( g->pimage[i], FALSE, FALSE );
	
	for ( i = 0; i < g->num_gen; i++ ) {
		l = strlen ( g->gen[i] );
		write_intlist ( (int)l, FALSE, FALSE );
		for ( j = 0; j < l; j++ )
			write_intlist ( g->gen[i][j], FALSE, FALSE );
	}	

	for ( i = 0; i < g->num_gen; i++ ) {
		for ( j = 0; j < g->num_gen; j++ )
			write_intlist (  g->nom[i][j], FALSE, FALSE );
	}	

	for ( i = 0; i < cnr; i++ )
		write_intlist ( g->c_len[i], FALSE, FALSE );
	for ( i = 0; i < g->num_gen; i++ )
		write_intlist ( g->p_len[i], FALSE, FALSE );

	for ( i = 0; i < cnr; i++ ) {
		if ( g->c_list[i] == NULL )
			write_intlist ( 0, FALSE, FALSE );
		else {
			for ( j = 0; j < g->c_len[i]+1; j++ ) {
				write_intlist ( g->c_list[i][j].g, FALSE, FALSE );
				write_intlist ( g->c_list[i][j].e, FALSE, FALSE );
			}
		}
	}
	
	for ( i = 0; i < g->num_gen; i++ ) {
		if ( g->p_list[i] == NULL )
			write_intlist ( 0, FALSE, FALSE );
		else {
			for ( j = 0; j < g->p_len[i]+1; j++ ) {
				write_intlist ( g->p_list[i][j].g, FALSE, FALSE );
				write_intlist ( g->p_list[i][j].e, FALSE, FALSE );
			}
		}
	}
	
	for ( i = 0; i < g->num_gen; i++ )
		node_to_code ( g->def_list[i] );
	
	write_intlist ( g->exp_p_class, FALSE, FALSE );
	for ( i = 0; i <= g->exp_p_class; i++ ) {
		write_intlist ( g->exp_p_lcs[i].i_start, FALSE, FALSE );
		write_intlist ( g->exp_p_lcs[i].i_end, FALSE, FALSE );
		write_intlist ( g->exp_p_lcs[i].i_dim, FALSE, FALSE );
	}
	
	for ( i = 0; i < g->num_gen-1; i++ )
		write_intlist ( g->pc_weight[i], FALSE, FALSE );
	
	if ( bracket ) {
		write_intlist ( g->pc_weight[g->num_gen-1], FALSE, TRUE );
		printf ( "%s", rec_postfx );
	}
	else
		write_intlist ( g->pc_weight[g->num_gen-1], FALSE, FALSE ); 
}


PCGRPDESC *code_to_pcgroup ( DYNLIST p )
{
	int i, j, l, cnr;
	PCGRPDESC *pc_desc = ALLOCATE ( sizeof ( PCGRPDESC ) );
	
	pc_desc->prime = p->value.intv; p = p->next;
	pc_desc->num_gen = p->value.intv; p = p->next;
	pc_desc->group_card = p->value.intv; p = p->next;
	pc_desc->max_id = p->value.intv; p = p->next;
	pc_desc->min_gen = p->value.intv; p = p->next;
	pc_desc->defs = p->value.intv; p = p->next;
	pc_desc->gen = ALLOCATE ( pc_desc->num_gen * sizeof ( char * ) );
	pc_desc->g_max = CALLOCATE ( pc_desc->num_gen * sizeof ( int ) );
	pc_desc->g_ideal = CALLOCATE ( pc_desc->num_gen * sizeof ( int ) );
	pc_desc->image = CALLOCATE ( pc_desc->num_gen * sizeof ( int ) );
	pc_desc->pimage = CALLOCATE ( pc_desc->num_gen * sizeof ( int ) );
	pc_desc->p_list = (ge_pair **)ALLOCATE ( pc_desc->num_gen * sizeof ( ge_pair *) );
	pc_desc->p_len = (int *)ALLOCATE ( pc_desc->num_gen * sizeof ( int ) );
	zero_vector ( pc_desc->group_name, 50 );
	for ( i = 0; i < 50; i++,p = p->next )
		pc_desc->group_name[i] = p->value.intv;
		
	for ( i = 0; i < pc_desc->num_gen; i++,p = p->next )
		pc_desc->g_max[i] = p->value.intv;

	for ( i = 0; i < pc_desc->num_gen; i++,p = p->next )
		pc_desc->g_ideal[i] = p->value.intv;
	for ( i = 0; i < pc_desc->num_gen; i++,p = p->next )
		pc_desc->image[i] = p->value.intv;
	for ( i = 0; i < pc_desc->num_gen; i++,p = p->next )
		pc_desc->pimage[i] = p->value.intv;

	cnr = ( pc_desc->num_gen * ( pc_desc->num_gen -1 ) ) >> 1;

	pc_desc->c_list = (ge_pair **)ALLOCATE ( cnr * sizeof ( ge_pair * ) );
	pc_desc->c_len = (int *)ALLOCATE ( cnr * sizeof ( int ) );
	pc_desc->def_list = ALLOCATE ( pc_desc->num_gen * sizeof ( GENDEF ) );
	pc_desc->pc_weight = ALLOCATE ( pc_desc->num_gen * sizeof ( int ) );
	pc_desc->exp_p_lcs = ALLOCATE ( (pc_desc->exp_p_class+1) * sizeof ( FILT ) );
	for ( i = 0; i < pc_desc->num_gen; i++ ) {
		l = p->value.intv; p = p->next;
		pc_desc->gen[i] = ALLOCATE ( l+1 );
		for ( j = 0; j < l; j++, p=p->next )
			pc_desc->gen[i][j] = p->value.intv;
		pc_desc->gen[i][l] = '\0';
	}	

	pc_desc->nom = ALLOCATE ( pc_desc->num_gen * sizeof ( PCELEM ) );
	for ( i = 0; i < pc_desc->num_gen; i++ ) {
		pc_desc->nom[i] = CALLOCATE ( pc_desc->num_gen );
		for ( j = 0; j < pc_desc->num_gen; j++, p=p->next )
			pc_desc->nom[i][j] = p->value.intv;
	}

	for ( i = 0; i < cnr; i++,p = p->next )
		pc_desc->c_len[i] = p->value.intv;
	for ( i = 0; i < pc_desc->num_gen; i++,p = p->next )
		pc_desc->p_len[i] = p->value.intv;

	for ( i = 0; i < cnr; i++ ) {
		if ( pc_desc->c_len[i] == 0 ) {
			pc_desc->c_list[i] = NULL;
			p = p->next;
		}
		else {
			pc_desc->c_list[i] = ALLOCATE ( (pc_desc->c_len[i]+1) * sizeof ( ge_pair ) );
			for ( j = 0; j < pc_desc->c_len[i]+1; j++, p=p->next ) {
				pc_desc->c_list[i][j].g = p->value.intv; p=p->next;
				pc_desc->c_list[i][j].e = p->value.intv;
			}
		}
	}
	
	for ( i = 0; i < pc_desc->num_gen; i++ ) {
		if ( pc_desc->p_len[i] == 0 ) {
			pc_desc->p_list[i] = NULL;
			p = p->next;
		}
		else {
			pc_desc->p_list[i] = ALLOCATE ( (pc_desc->p_len[i]+1) * sizeof ( ge_pair ) );
			for ( j = 0; j < pc_desc->p_len[i]+1; j++, p=p->next ) {
				pc_desc->p_list[i][j].g = p->value.intv; p=p->next;
				pc_desc->p_list[i][j].e = p->value.intv;
			}
		}
	}
	
	pp = p;
	for ( i = 0; i < pc_desc->num_gen; i++ )
		pc_desc->def_list[i] = code_to_node();

	p = pp;
	pc_desc->exp_p_class = p->value.intv; p = p->next;
	
	pc_desc->exp_p_lcs = ALLOCATE ( (pc_desc->exp_p_class+1) * sizeof ( FILT ) );
	for ( i = 0; i <= pc_desc->exp_p_class; i++,p = p->next ) {
		pc_desc->exp_p_lcs[i].i_start = p->value.intv; p=p->next;
		pc_desc->exp_p_lcs[i].i_end = p->value.intv; p=p->next;
		pc_desc->exp_p_lcs[i].i_dim = p->value.intv;
	}	
	for ( i = 0; i < pc_desc->num_gen; i++,p = p->next )
		pc_desc->pc_weight[i] = p->value.intv;
	pc_desc->autg = NULL;
	pp = p;
	
	return ( pc_desc );
}

void hom_to_code ( HOM *a )
{
	int i, j, l, numgen;
	PCGRPDESC *g = a->g;
	char *rec_prefx, *rec_postfx;

	if ( a->auts == 0 && !a->elements )
		return;

	if ( displaystyle == GAP ) {
		rec_prefx = "SISYPHOS.SISCODE :=  [";
		rec_postfx = "];\n";
	}
	else {
		rec_prefx = "[";
		rec_postfx = "]\n";
	}
	
	numgen = g->defs ? g->min_gen : g->num_gen;
	printf ( "%s%d,\n", rec_prefx, HOMREC );
	pcgroup_to_code ( g, FALSE );	
	write_intlist ( a->auts, FALSE, FALSE );
	write_intlist ( a->class1_generators, FALSE, FALSE );
	write_intlist ( a->inn_log, FALSE, FALSE );
	write_intlist ( a->out_log, FALSE, FALSE );
	write_intlist ( a->only_normal_auts, FALSE, FALSE );
	write_intlist ( a->with_inner, FALSE, FALSE );

	for ( i = 1; i <= g->exp_p_class; i++ )
		write_intlist ( a->aut_gens_dim[i], FALSE, FALSE );
	for ( i = 1; i <= g->exp_p_class; i++ )
		write_intlist ( a->out_gens_dim[i], FALSE, FALSE );

	for ( i = 1; i <= g->exp_p_class; i++ ) {
		for ( j = 0; j < a->aut_gens_dim[i]; j++ )
			for ( l = 0; l < g->num_gen * numgen; l++ )
				write_intlist ( a->aut_gens[i][j][l], FALSE, FALSE );
	}
	
	write_intlist ( a->elements, FALSE, TRUE );
	printf ( "%s", rec_postfx );
}

HOM *code_to_hom ( DYNLIST p )
{
	int i, j, l, numgen;
	HOM *a = ALLOCATE ( sizeof(HOM) );
	PCGRPDESC *g;
	
	/* skip id */
	p = p->next;
	a->g = g = code_to_pcgroup ( p );
	p = pp;

	numgen = g->defs ? g->min_gen : g->num_gen;
	a->h = NULL;
	a->auts = p->value.intv; p = p->next;
	a->class1_generators = p->value.intv; p = p->next;
	a->inn_log = p->value.intv; p = p->next;
	a->out_log = p->value.intv; p = p->next;
	a->only_normal_auts = p->value.intv; p = p->next;
	a->with_inner = p->value.intv; p = p->next;

	a->aut_gens_dim = tallocate ( (g->exp_p_class+1) * sizeof ( int ) );
	a->out_gens_dim = tallocate ( (g->exp_p_class+1) * sizeof ( int ) );
	a->aut_gens = tallocate ( (g->exp_p_class+1) * sizeof ( VEC* ) );
	a->epimorphism = NULL;

	a->stabs = NULL;

	for ( i = 1; i <= g->exp_p_class; i++,p=p->next )
		a->aut_gens_dim[i] = p->value.intv;
	for ( i = 1; i <= g->exp_p_class; i++,p=p->next )
		a->out_gens_dim[i] = p->value.intv;

	for ( i = 1; i <= g->exp_p_class; i++ ) {
		a->aut_gens[i] = tallocate ( a->aut_gens_dim[i] * sizeof ( VEC ) );
		for ( j = 0; j < a->aut_gens_dim[i]; j++ )
			a->aut_gens[i][j] = tallocate ( g->num_gen * numgen);
	}	
		
	for ( i = 1; i <= g->exp_p_class; i++ ) {
		for ( j = 0; j < a->aut_gens_dim[i]; j++ )
			for ( l = 0; l < g->num_gen * numgen; l++, p=p->next )
				a->aut_gens[i][j][l] = p->value.intv;
	}
	a->elements = p->value.intv;
	
	return ( a );
}

