/********************************************************************/
/*                                                                  */
/*  Module        : Group ring conjugation                          */
/*                                                                  */
/*  Version       : 2.8                                             */
/*  Last revision : 10/23/92 14:29:24                               */
/*                                                                  */
/*  Description :                                                   */
/*     Allows to compute Z1 modulo cocycles stemming from conjuga-  */
/*     gation with 1 + I/I^n.                                       */
/*                                                                  */
/*  Functions supplied :                                            */
/*     int handle_conj ( VEC args[], VEC z1[], int z1dim );         */
/*                                                                  */
/********************************************************************/

#include <ctype.h>
#include "aglobals.h"
#include "fdecla.h"
# include	"pc.h"
# include	"grpring.h"
# include	"hgroup.h"
# include	"storage.h"

VEC gr_invers 				_(( VEC elem, int mod_id ));

extern PCGRPDESC *group_desc;
extern GRPRING *group_ring;
extern GRPDSC *h_desc;
extern int s_int;
extern char matrix[YMAX][XMAX];
extern VEC absolut, inhom;
extern VEC fsolution[XMAX];
extern int x_dim, y_dim, yh_dim, fend;
extern int new_xdim, new_cut;
extern IHEADER h_out;
extern int verbose;
extern FILE *proto;

#define MAXCENT 1024

VEC centre[MAXCENT];
VEC i_centre[MAXCENT];
int cent_dim;

void centralizer ( VEC args[], int mod_id, int argn )
{
	register int i, j, k;
	int pre_dim, xd, yd;
	VEC r_left, r_right, x;
	int offset;
	
	xd = FILTRATION[mod_id].i_start;
	pre_dim = FILTRATION[mod_id-1].i_start;
	yd = pre_dim * argn;
	absolut = CALLOCATE ( yd );
	inhom = ALLOCATE ( xd );
	x = ALLOCATE ( xd );
	for ( j = 0; j < xd; j++ ) {
		offset = 0;
		zero_vector ( x, xd );
		x[j] = 1;
		for ( i = argn; i--; ) {
			r_left = GROUP_MUL ( args[i], x, mod_id );
			r_right = GROUP_MUL ( x, args[i], mod_id );
			SUBA_VECTOR ( r_left, r_right, pre_dim );
			for ( k = pre_dim; k--; ) 
				matrix[(long)(k+offset)][(long)j] = r_right[k];
			offset += pre_dim;
		}
	}
	cent_dim = xd - solve_equations ( xd, yd );
	j = 0;
	for ( i = 0; i < xd; i++ ) {
		if ( fsolution[i] ) {
			centre[j] = ALLOCATE ( xd );
			copy_vector ( fsolution[i], centre[j], xd );
			centre[j][0] = 1;
			i_centre[j] = gr_invers ( centre[j], mod_id );
			j++;
		}
	}
	if ( proto != NULL )
		fprintf ( proto, "   dim of centre  = %d \n", cent_dim );
	if ( verbose )
		printf ( "dim of centralizer = %d\n", cent_dim );
}		

SPACE *e_centralizer ( VEC args[], int n_args, int mod_id )
{
	register int i, j, k;
	VEC r_left, r_right, x;
	int offset, xd, yd;
	char *old_top;
	long mem_offset;
	SPACE *v_cent = (SPACE *)ALLOCATE ( (int)sizeof ( SPACE ) );
	VEC p;

	xd = FILTRATION[mod_id].i_start;
	yd = xd * n_args;
	old_top = GET_TOP();
	p = ALLOCATE ( (long)xd * xd );
	v_cent->total_dim = xd;
	v_cent->b_flag = UPPER;
	v_cent->basis = p;
	
	absolut = CALLOCATE ( yd );
	inhom = ALLOCATE ( xd );
	x = ALLOCATE ( xd );
	for ( j = 0; j < xd; j++ ) {
		offset = 0;
		zero_vector ( x, xd );
		x[j] = 1;
		for ( i = n_args; i--; ) {
			r_left = GROUP_MUL ( args[i], x, mod_id );
			r_right = GROUP_MUL ( x, args[i], mod_id );
			SUBA_VECTOR ( r_left, r_right, xd );
			for ( k = xd; k--; ) 
				matrix[(long)(k+offset)][(long)j] = r_right[k];
			offset += xd;
		}
	}
	cent_dim = xd - solve_equations ( xd, yd );
	j = 0;
	for ( i = 0; i < xd; i++ ) {
		if ( fsolution[i] ) {
			copy_vector ( fsolution[i], p, xd );
			SMUL_VECTOR ( GPRIME-1, p, xd );
			j++;
			p += xd;
		}
	}
	v_cent->dimension = j;
	mem_offset = j * xd;
	mem_offset += ( mem_offset & 1L );
	SET_TOP ( old_top + mem_offset );

	return ( v_cent );
}		

int handle_conj ( VEC rho[] )
{
	int offset;
	register int i, j;
	int ydim = 0;
	VEC help, conj_vec, rhohom;

	conj_vec = ALLOCATE ( new_xdim );
	rhohom = CALLOCATE ( h_out.old_end );
	
	/* compute conjugates */
	for ( i = 1; i < cent_dim; i++ ) {
		offset = new_xdim;
		for ( j = NUMGEN; j--; ) {
			offset -= h_out.old_dim;
			copy_vector ( rho[j], rhohom, h_out.old_start );
			help = GROUP_MUL ( i_centre[i], rhohom, new_cut );
			help = GROUP_MUL ( help, centre[i], new_cut );
			copy_vector ( help+h_out.old_start, conj_vec+offset,
					  h_out.old_dim );
		}
		if ( !iszero ( conj_vec, new_xdim ) )
			copy_vector ( conj_vec, matrix[(long)ydim++], new_xdim );
	}
	return ( ydim );
}
	
/* end of module group ring conjugation */
