#include "def.h"
#include "macro.h"
#define callocobject callocobject_trace
#undef callocobject
static struct partition * callocpartition();
static int utiliser();
static int repartir();
static INT ordcon_char();
static INT m060588();
static INT m060588b();
static INT mem_counter_part=(INT)0; /* AK 100893 */

static struct partition **pa_sp = NULL;  /* speicher fuer partitionen */
static INT pa_index = -1L;

#define PASIZE (INT)1000

#ifdef VECTORTRUE
#define M_KL_PA(a,b,c) (b_ks_pa(a,callocobject(),c) || m_l_v(b,S_PA_S(c)))
#define B_KL_PA(a,b,c) (b_ks_pa(a,callocobject(),c) || b_l_v(b,S_PA_S(c)))
#endif /* VECTORTRUE */

#define PART_CHECK_KIND(t,a,b)\
	if (S_O_K(a) != PARTITION)\
		WTO(t,a);\
	if (S_PA_K(a) != b)\
		wrong_kind_part(t,a,b);

#ifdef PARTTRUE
	INT t_CHARPARTITION_PARTITION();
static char * part_kind_to_text(k) OBJECTKIND k;
{
	switch(k)
		{
		case EXPONENT:	return "exponent";
		case VECTOR:	return "vector";
		case BITVECTOR:	return "bitvector";
		case FROBENIUS:	return "frobenius";
		default:	return "unknown";
		}
}

static INT wrong_kind_part(t,a,b) char *t; OP a; OBJECTKIND b;
{
	char s[200];
	sprintf(s,"%s: wrong kind of partition, should be %s but it was %s",
		t,part_kind_to_text(b),part_kind_to_text(S_PA_S(a)));
	error(s);
	return ERROR;
}


INT inc_partition(a) OP a;
	{
	return inc_vector(s_pa_s(a));
	}

INT m_i_staircase(a,b) OP a,b;
{
	INT i;
	b_ks_pa(VECTOR,callocobject(),b);
	m_l_v(a,S_PA_S(b));
	for (i=0;i<S_PA_LI(b);i++)
		M_I_I(i+1,S_PA_I(b,i));

}

INT partitionp(a) OP a;
/* AK 170692 */
{
	INT i;
	if ( S_O_K(a) == CHARPARTITION) /* AK 170593 */
		{
		INT m=1L;
		for (i=(INT)0;i<S_PA_CL(a); i++)
			{
			if (S_PA_CII(a,i) < m) return FALSE;
			m = S_PA_CII(a,i);
			}
		return TRUE;
		}
	if ( S_O_K(a) != PARTITION ) return FALSE;
	if ( S_PA_K(a) == VECTOR )
		{
		INT m=1L;
		for (i=(INT)0;i<S_PA_LI(a); i++)
			{
			if (S_O_K(S_PA_I(a,i)) != INTEGER) return FALSE;
			if (S_PA_II(a,i) < m) return FALSE;
			m = S_PA_II(a,i);
			}
		return TRUE;
		}
	if ( S_PA_K(a) == EXPONENT )
		for (i=(INT)0;i<S_PA_LI(a); i++)
			if (S_O_K(S_PA_I(a,i)) != INTEGER) return FALSE;
	if (S_PA_K(a) == BITVECTOR )
		return TRUE;
	return FALSE;
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT strictp(a) OP a;
/* AK 300792   true if no equal parts */
{
	INT i;	
	INT erg = OK;
	CTO(PARTITION,"stricp",a);
	if (S_PA_K(a) == VECTOR)
		{
		for (i=1L;i<S_PA_LI(a);i++)
			if (S_PA_II(a,i) == S_PA_II(a,i-1L))
				return FALSE;
		return TRUE;
		}
	else if (S_PA_K(a) == EXPONENT)
		{
		for (i=(INT)0;i<S_PA_LI(a);i++)
			if (S_PA_II(a,i) > 1L) return FALSE;
		return TRUE;
		}
	else
		return error("strictp:wrong type of partiton");
	ENDR("strictp");
}


INT add_part_part(a,b,c) OP a,b,c;
/* c = a + b */ /* AK 071189 */ /* AK 181289 V1.1 */ /* AK090891 V1.3 */
/* componenten weise */
{
	INT i,j;
	INT erg = OK;
	if (not EMPTYP(c)) 
		erg += freeself(c);

	PART_CHECK_KIND("add_part_part",a,VECTOR);
	PART_CHECK_KIND("add_part_part",b,VECTOR);

	if (le(S_PA_L(a),S_PA_L(b))) {
		erg += copy_partition(b,c);
		for (i=S_PA_LI(a)-1L,j=S_PA_LI(b)-1L;i>=(INT)0;i--,j--)
			erg += add(S_PA_I(a,i),S_PA_I(b,j),S_PA_I(c,j));
		goto appende;
	}
	erg += copy_partition(a,c);
	for (i=S_PA_LI(a)-1L,j=S_PA_LI(b)-1L;j>=(INT)0;i--,j--)
		erg += add(S_PA_I(a,i),S_PA_I(b,j),S_PA_I(c,i));

appende:
	ENDR("add_part_part");
}

INT remove_part_part(a,b,c) OP a,b,c;
/* AK 070995 */
/* 23344 , 24 ->> 334 */
{
	INT erg = OK;
	INT i,j,k;
	OP d ;
        if (check_equal_3(a,b,c,remove_part_part,&erg) == EQUAL)
                goto eee;
	if (emptyp(b))
		{
		erg += copy(a,c);
		goto eee;
		}
	d = callocobject();
	erg += m_il_nv(S_PA_LI(a),d);
	for (i=0,j=0,k=0;i<S_PA_LI(a);i++)
		{
aaa:
		if (j==S_PA_LI(b))
			{
			erg += m_i_i(S_PA_II(a,i), S_V_I(d,k));
			k++;
			}
		else if (S_PA_II(a,i) == S_PA_II(b,j)) 
			{
			j++;
			}
		else if (S_PA_II(a,i) < S_PA_II(b,j))
			{
			erg += m_i_i(S_PA_II(a,i), S_V_I(d,k));
			k++;
			}
		else	{
			j++;
			goto aaa;
			}
		}
	erg += m_v_pa(d,c);
	erg += SYMfreeall(d);
eee:
	ENDR("remove_part_part");
}

INT append_part_part(a,b,c) OP a,b,c;
/* AK 090891 V1.3 */
/* join the parts to one partition */
/* e.g. 233, 1224 --> 1222334 */
{
	OP d;
	INT erg = OK;
	if (S_O_K(b) != PARTITION) /* AK 040292 */
		return error("append_part_part: second OP  != PARTITION");
	d = callocobject();
	erg += append(S_PA_S(a),S_PA_S(b),d);
	erg += m_v_pa(d,c);
	erg += SYMfreeall(d);
	ENDR("append_part_part");
}
#endif /* PARTTRUE */ 

#ifdef PARTTRUE
INT add_partition(a,b,c) OP a,b,c;
/* AK 060789 V1.0 */ /* AK 280590 V1.1 */ /* AK 200891 V1.3 */
{
	INT erg = OK; /* AK 040292 */
	switch(S_O_K(b))
	{
	case PARTITION : erg += add_part_part(a,b,c); break;
#ifdef SCHURTRUE
	case SCHUR : erg += m_pa_s(a,c); 
		erg+=add(c,b,c); 
		break;
#endif /* SCHURTRUE */
	default : 
		{ 	
		printobjectkind(b);
		return error("add_partition:wrong second type");
		};
	}
	ENDR("add_partition");
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT first_composition(w,parts,c) OP parts, w, c;
/* AK 090487 */ /* AK 201189 V1.1 */ /* AK 150591 V1.2 */ /* AK 200891 V1.3 */
{
	INT i,erg=OK;
	if (not EMPTYP(c)) 
		erg += freeself(c);
	erg += m_il_v(S_I_I(parts),c);
	erg += copy(w,S_V_I(c,(INT)0));
	for (i=1L;i<S_V_LI(c);M_I_I((INT)0,S_V_I(c,i)),i++);
	C_O_K(c,COMP);
	ENDR("first_composition");
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT next_composition(c,newcomp) OP c, newcomp;
/* AK 300889 */ /* AK 201189 V1.1 */ /* AK 200891 V1.3 */
{
	INT i,j,rest;
	/* c ist ein vector */
	/* newcomp ist ein vector */
	copy(c,newcomp);
	for (i=S_V_LI(newcomp)-2L,j=i+1L,rest=(INT)0; i>=(INT)0; i--,j--)
		if (S_V_II(newcomp,i) == (INT)0)
		{
			rest += S_V_II(newcomp,j);
			C_I_I(S_V_I(newcomp,j),(INT)0);
		}
		else if (S_V_II(newcomp,i) > (INT)0)
		{
			DEC_INTEGER(S_V_I(newcomp,i));
			C_I_I(S_V_I(newcomp,j),S_V_II(newcomp,j)+1L+rest);
			return(OK);
		};
	return(LASTCOMP);
}
#endif /* PARTTRUE */


#ifdef PARTTRUE
INT fastconjugate_partition(part,b) OP part, b;
/* AK 220587 */
/* konjugierte einer partition nach satz in macdonald
aber auch nicht viel schneller als conjugatepartition */
/* AK 060789 V1.0 */ /* AK 240490 V1.1 */ /* AK 200891 V1.3 */
{
	INT i,j,k=(INT)0,m;
	/* k ist die adresse an der geschrieben wird im b */
	INT erg = OK;

	if (S_O_K(part) != PARTITION) return ERROR;  /* AK 170692 */
	if (S_PA_K(part) == EXPONENT)  /* AK 170692 */
		{
		OP c = callocobject();
		erg += t_EXPONENT_VECTOR(part,c);
		erg += fastconjugate_partition(c,b);
		erg += SYMfreeall(c);
		erg += t_VECTOR_EXPONENT(b,b);
		return erg;
		}
	if (S_PA_K(part) != VECTOR) return ERROR;  /* AK 170692 */

	b_ks_pa(VECTOR,callocobject(),b);
	// Patch by NT in case part is the empty partition 08/11/2004
	m_il_v(// the length of the conjugate partition:
	       (S_PA_LI(part) > 0) ? S_PA_II(part,S_PA_LI(part)-1L) : 0,
	       S_PA_S(b));

	j = S_PA_LI(part) - 1L;
	/* dies sind die adressen in den beiden partitionen */
	m = S_PA_LI(b)+S_PA_LI(part)+1L;
	/* dies ist die laenge der permutation + 1 */
	for(	i=m-1L; i > (INT)0 ; i--)
	{
		if (j>=0)
			if (i == S_PA_II(part,j)+j+1L ) j-- ;
			else {
				M_I_I(m-i- k - 1L,S_PA_I(b,k));
				k++ ;
			}
		else	{
			M_I_I(m-i- k - 1L,S_PA_I(b,k));
			k++ ;
		}
	}
	return(OK);
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT ferrers_partition(part) OP part;
/* AK 060789 V1.0 */ /* AK 150690 V1.1 */ /* AK 200891 V1.3 */
{
	INT i,j;
	INT erg = OK;
	PART_CHECK_KIND("ferrers_partition",part,VECTOR);

	printf("\n");
	for (i=(INT)0; i<S_PA_LI(part);i++)
	{
		for (j=(INT)0;j<S_PA_II(part,i);j++) printf("**** ");
		printf("\n");
		for (j=(INT)0;j<S_PA_II(part,i);j++) printf("**** ");
		printf("\n\n");
	};
	zeilenposition = (INT)0;
	ENDR("ferrers_partition");
}
#endif  /* PARTTRUE */

#ifdef PARTTRUE
INT fprint_partition(f,partobj) FILE	*f; OP partobj;
/* AK 140587 */ /* AK 060789 V1.0 */ /* AK 290890 V1.1 */ /* AK 200891 V1.3 */
{
	INT i;
	INT erg = OK;
	if (S_PA_K(partobj) == FROBENIUS) /* AK 101292 */
		{
		fprint(f,S_PA_S(partobj));
		goto endr_ende;
		}
	else if (S_PA_K(partobj) == BITVECTOR)
                {
		fprint(f,S_PA_S(partobj));
		goto endr_ende;
		}
	
	for(	i = (INT)0; i<S_PA_LI(partobj); i++)
		if (S_PA_II(partobj,i)<10)
		/*AK partitionsteile kleiner 10 werden als Zahlen geschrieben */
		{ 
			fprintf(f,"%d",S_PA_II(partobj,i));
			if (f == stdout) zeilenposition++; 
		}
		else if (S_PA_II(partobj,i)<16)
		/* A.K. partitionsteile von 10 bis 15 werden als 
			A,B,C,D,E,F geschrieben */
		{ 
			fprintf(f,"%c",S_PA_II(partobj,i)+55);
			if (f == stdout) zeilenposition++; 
		}
		else	{
			/* A.K. sonst werden die Teile als zahl mit 
			abschliessenden senkrechten Strich geschrieben */
			fprintf(f,"%c%d",'|',S_PA_II(partobj,i));
			if(f==stdout) 
				zeilenposition+=(1+intlog(S_PA_I(partobj,i)));
			};
	if ((f == stdout)&&(zeilenposition>(INT)70))
	{ 
		fprintf(f,"\n"); 
		zeilenposition = (INT)0; 
	}
	ENDR("fprint_partition");
}

INT sprint_partition(f,partobj) char	*f; OP partobj;
{
	INT i;
	INT erg = OK;
	if (S_PA_K(partobj) == FROBENIUS) /* AK 101292 */
		{
		sprint(f,S_PA_S(partobj));
		goto endr_ende;
		}
	else if (S_PA_K(partobj) == BITVECTOR)
                {
		sprint(f,S_PA_S(partobj));
		goto endr_ende;
		}
	
	for(	i = (INT)0; i<S_PA_LI(partobj); i++)
		if (S_PA_II(partobj,i)<10)
		/*AK partitionsteile kleiner 10 werden als Zahlen geschrieben */
		{ 
			sprintf(f,"%d",S_PA_II(partobj,i));
			f++; 
		}
		else if (S_PA_II(partobj,i)<16)
		/* A.K. partitionsteile von 10 bis 15 werden als 
			A,B,C,D,E,F geschrieben */
		{ 
			sprintf(f,"%c",S_PA_II(partobj,i)+55);
			f++; 
		}
		else	{
			/* A.K. sonst werden die Teile als zahl mit 
			abschliessenden senkrechten Strich geschrieben */
			sprintf(f,"%c%d",'|',S_PA_II(partobj,i));
			f+=(1+intlog(S_PA_I(partobj,i)));
			};
	ENDR("sprint_partition");
}
#endif /* PARTTRUE */


#ifdef PARTTRUE
INT gupta_nm(n,m,res) OP n,m,res;
/* AK 220888 
	vgl. Hansraj Gupta Proc London Math Soc 2 (39)
	1935 142-149 dort werden die Anzahlen der Partitionen von n
	bis n=300 aufgelistet. Zur Berechnung mittels einer
	Rekurssion werden die Zahlen (n,m) = Anzahl der Partitionen
	von n mit dem kleinsten Teil = m benoetigt
	Diese werden rekursiv berechnet, diese Zahlen 
	werden auch von dieser Prozedur berechnet
	*/
/* AK 060789 V1.0 */ /* AK 120390 V1.1 */ /* AK 200891 V1.3 */
{
	OP i,j,zw;


	if (not EMPTYP(res)) 
		if (S_O_K(res) != INTEGER) freeself(res);

	if (S_I_I(n) == S_I_I(m)) 
		return(M_I_I(1L,res));
	if (S_I_I(m) > S_I_I(n)/2L) 
		return(M_I_I((INT)0,res));

	i = callocobject(); j = callocobject(); zw = callocobject();
	/* initialisieren i = n-m, j = m, res = 0 */
	M_I_I(S_I_I(n)-S_I_I(m),i); 
	COPY_INTEGER(m,j); 
	M_I_I((INT)0,res);
	
	while(S_I_I(j) <= S_I_I(i) )
	{ 
		gupta_nm(i,j,zw); 
		if (S_O_K(zw) != INTEGER) add_apply(zw,res); 
		else if (not NULLP_INTEGER(zw)) add_apply(zw,res); 
		/* nicht aufrufen falls 0 */
		INC_INTEGER(j); 
	}

	SYMfreeall(zw); 
	SYMfreeall(i); SYMfreeall(j);
	return(OK);
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
#ifdef MATRIXTRUE
INT gupta_tafel(mx,mat) OP mx,mat;
/* AK 220888 */
/* berechnet partitionen bis n=mx */
/* erstellt tafel */
/* AK 060789 V1.0 */ /* AK 120390 V1.1 */ /* AK 200891 V1.3 */
{
	INT i,j,k;
	OP h = callocobject();
	OP l = callocobject();
	OP zw = callocobject();

	M_I_I(S_I_I(mx),h); 
	M_I_I((S_I_I(mx) / 2L)+1L,l);

	b_lh_m(l,h,mat); /* da sollen zahlen rein */

	for (i=(INT)0; i< S_I_I(mx); i++)
	{
		for (j=(INT)0;j<=i/2L;j++)
		{
			freeself(zw);
			M_I_I((INT)0,zw);
			for (k=(INT)0; j+k < (i-j)/2L ; k++)
			/* die rekursion */
			{
				add_apply(S_M_IJ(mat,i-j-1L,j+k),zw);
			}
			inc(zw);
			copy(zw,S_M_IJ(mat,i,j));
		};
	}

	SYMfreeall(zw);
	return(OK);
}
#endif /* MATRIXTRUE */
#endif /* PARTTRUE */

INT gupta_nm_speicher(n,m,res) OP n,m,res;
/* AK 220888 mit speicher */
/* AK 120390 V1.1 */ /* AK 200891 V1.3 */
{
#ifdef MATRIXTRUE
#ifdef PARTTRUE
	OP mat;

	if (S_I_I(n) == S_I_I(m)) 
		return(M_I_I(1L,res));
	if (S_I_I(m) > S_I_I(n)/2L) 
		return(M_I_I((INT)0,res));

	mat = callocobject();
	gupta_tafel(n,mat);
	copy(S_M_IJ(mat,S_I_I(n)-1L,S_I_I(m)-1L),res);
	SYMfreeall(mat);
	return(OK);
#endif  /* PARTTRUE */
#else /* MATRIXTRUE */
	return error("gupta_nm_speicher: MATRIX not available");
#endif /* MATRIXTRUE */
}

#ifdef PARTTRUE
INT hook_length_augpart(p,i,j,res) OP p,res; INT i,j;
/* AK 060988 hakenlaenge */ 
/* AK 060789 V1.0 */ /* AK 080290 V1.1 */ /* AK 200891 V1.3 */
{
	INT e,k;
	if (not EMPTYP(res)) 
		if (S_O_K(res) != INTEGER) 
			freeself(res);
	if (i >= S_PA_LI(p)) 
		return(M_I_I((INT)0,res));
	if (j >= S_PA_II(p,i)-i) 
		return(M_I_I((INT)0,res));
	e = S_PA_II(p,i) - j - i;
	/* nun noch die zeilen dazu */
	for (k=i-1L; k>= (INT)0; k--)
		if (S_PA_II(p,k) -1L -k >= j) 
			e++;
		else break;
	return(M_I_I(e,res));
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT hook_diagramm(p,m) OP p,m;
/* AK 010295 */
{
	INT erg = OK, i,j;
        if (check_equal_2(p,m,hook_diagramm,&erg) == EQUAL)
                goto ee;
	if (S_O_K(p) != PARTITION) 
		return WTO("hook_diagramm",p);
	if (S_PA_K(p) != VECTOR)
		return ERROR;
	erg += m_ilih_m(S_PA_II(p,S_PA_LI(p)-1), S_PA_LI(p), m);
	for (i=0L;i<S_M_HI(m);i++)
	for (j=0L;j<S_M_LI(m);j++)
		erg += hook_length(p,i,j,S_M_IJ(m,i,j));
ee:
	ENDR("hook_diagramm");
}

INT hook_length(p,i,j,b) OP p,b; INT i,j;
/* AK 060988 hakenlaenge */ 
/* AK 060789 V1.0 */ /* AK 150690 V1.1 */ /* AK 200891 V1.3 */
{
	INT e,k;
	INT erg = OK;
	CTO(PARTITION,"hook_length",p);
	if (S_PA_K(p) == EXPONENT)  /* AK 170692 */
		{
		OP c = callocobject();
		e = t_EXPONENT_VECTOR(p,c);
		e += hook_length(c,i,j,b);
		e += SYMfreeall(c);
		return e;
		}
	if (S_PA_K(p) != VECTOR)
		return ERROR;

	if (not EMPTYP(b)) 
		if (S_O_K(b) != INTEGER)
			erg += freeself(b);
	if (i >= S_PA_LI(p)) 
		return(M_I_I((INT)0,b), OK);
	if (j >= S_PA_II(p,S_PA_LI(p)-1L-i)) 
		return(M_I_I((INT)0,b), OK);
	e = S_PA_II(p,S_PA_LI(p)-1L-i) - j;
	/* nun noch die zeilen dazu */
	for (k=i+1L; k<S_PA_LI(p); k++) 
		if (S_PA_II(p,S_PA_LI(p)-1L-k) -1L >= j) e++;
		else break;
	M_I_I(e,b);
	ENDR("hook_length");
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT dimension_partition(a,b) OP a,b;
/* AK 150988 */
/* es wird die dimension des durch die partition bezeichneten Characters der Sn
berechnet. Dazu wird die hakenformel verwendet */
/* AK 060789 V1.0 */ /* AK 080290 V1.1 */ /* AK 050391 V1.2 */ 
/* AK 200891 V1.3 */
{
	OP zaehler, nenner,  zw;
	INT i,j;
	INT erg = OK;

	if (S_O_K(a) != PARTITION) 
		{
		WTO("dimension_partition",b);
		goto ende;
		}

	if (S_PA_K(a) == EXPONENT) /* AK 170692 */
		{
		zw = callocobject();
		erg += t_EXPONENT_VECTOR(a,zw);
		erg += dimension_partition(zw,b);
		erg += SYMfreeall(zw);
		goto ende;
		}
	if (S_PA_K(a)  != VECTOR) 
		{
		error("dimension_partition: wrong kind of partition");
		erg = ERROR;
		goto ende;
		}

	zw = callocobject();
	zaehler = callocobject();
	erg = weight(a,zw);

	erg += fakul(zw,zaehler);
	erg += freeself(zw);
	nenner = callocobject(); 
	erg += M_I_I(1L,nenner);
	for (i=(INT)0;i<S_PA_LI(a);i++)
		for (j=(INT)0;j<S_PA_II(a,S_PA_LI(a)-1L-i);j++)
		{
			erg += hook_length(a,i,j,zw);
			erg += mult_apply(zw,nenner);
		};
	erg += SYMfreeall(zw);
	erg += ganzdiv(zaehler,nenner,b); /* statt div3 AK 170889 */
	erg += SYMfreeall(zaehler);
	erg += SYMfreeall(nenner);
ende:
	ENDR("dimension_partition");
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT dimension_augpart(a,b) OP a,b;
/* a ist an object of type AUGPART
   b becomes the dimension of the corresponding irred representation */
/* AK 060789 V1.0 */ /* AK 120390 V1.1 */ /* AK 250291 V1.2 */
/* AK 200891 V1.3 */
{
	OP zaehler;
	OP nenner;
	OP zw;
	
	INT i,j,erg = OK;


	if (not EMPTYP(b))
	if (S_O_K(b) != INTEGER) 
		erg += freeself(b); 
	else 
		C_O_K(b,(OBJECTKIND)0);

	if (S_PA_LI(a) == 1L)
		return M_I_I(1L,b);
	if (S_PA_II(a,S_PA_LI(a)-1L) == S_PA_LI(a)) /* 1^n */
		return M_I_I(1L,b);
	if (S_PA_II(a,S_PA_LI(a)-2L) == S_PA_LI(a)-2L) /* n */
		return M_I_I(1L,b);

	if (S_PA_LI(a)==2L)
		{
		if (S_PA_II(a,(INT)0)==1L)
			return M_I_I(S_PA_II(a,1L)-1L,b);
		}


	zaehler = callocobject();
	nenner = callocobject();
	zw = callocobject();


	erg += weight_augpart(a,zw);

	erg += fakul(zw,zaehler);

	if (S_O_K(zw) != INTEGER) 
		erg += freeself(zw); 
	else 
		C_O_K(zw,(OBJECTKIND)0);

	M_I_I(1L,nenner);
	for (i=(INT)0;i<S_PA_LI(a);i++)
		for (j=(INT)0;j<S_PA_II(a,i)-i;j++)
		{
			erg += hook_length_augpart(a,i,j,zw);
			if (S_I_I(zw) != 1L)
				erg += mult_apply_integer(zw,nenner);
		};

	erg += SYMfreeall(zw); 
	if ((S_O_K(zaehler) == INTEGER) && (S_O_K(nenner) == INTEGER)) /* AK 151294 */
		M_I_I(S_I_I(zaehler) / S_I_I(nenner) ,b);
	else
		erg += ganzdiv(zaehler,nenner,b); /* statt div3 AK 170889 */
	erg += SYMfreeall(zaehler); 
	erg += SYMfreeall(nenner); 
	ENDR("dimension_augpart");
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT last_part_EXPONENT(n,part) OP n,part;
/* AK 150888 */ /* AK 060789 V1.0 */ /* AK 281189 V1.1 */
/* AK 200891 V1.3 */
{
	INT i;
	INT erg = OK;

	erg += b_ks_pa(EXPONENT,callocobject(),part);
	erg += m_il_v(S_I_I(n),S_PA_S(part));

	M_I_I(S_PA_LI(part), S_PA_I(part,(INT)0));
	/* hier war ein fehler in V1.0 */
	for (i=1L; i<S_PA_LI(part);i++) M_I_I((INT)0,S_PA_I(part,i));
	ENDR("last_part_EXPONENT");
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT first_part_VECTOR(n,part) OP n,part; 
/* AK 200891 V1.3 */
	{
	return first_partition(n,part);
	}
#endif /* PARTTRUE */
#ifdef PARTTRUE
INT last_part_VECTOR(n,part) OP n,part; 
/* AK 200891 V1.3 */
	{return last_partition(n,part);}
#endif /* PARTTRUE */



INT first_part_EXPONENT(n,part) OP n,part;
/* AK 150888 */ /* AK 060789 V1.0 */ /* AK 121190 V1.1 */
/* AK 200891 V1.3 */
{
#ifdef PARTTRUE
	INT i;
	INT erg = OK; /* AK 020692 */

	erg += b_ks_pa(EXPONENT,callocobject(),part);
	erg += m_l_v(n,S_PA_S(part));

	for (i=(INT)0; i<S_PA_LI(part)-1L;i++) 
		M_I_I((INT)0,S_PA_I(part,i));
	M_I_I(1L, S_PA_I(part,S_PA_LI(part)-1L));
	return erg;
#else /* PARTTRUE */
	return error("first_part_EXPONENT:PARTITION not available");
#endif /* PARTTRUE */
}



#ifdef PARTTRUE
INT last_partition(n,part) OP n,part;
/* AK 190587 */
/* die prozedur erzeugt aus der Zahl n die Partition
[1^n], die letzte Partition bezueglich nextpartition
bzgl. Dominanzordnung und auch lexikographisch */
/* n wird nicht verwendet */
/* AK 060789 V1.0 */ /* AK 300590 V1.1 */ /* AK 200891 V1.3 */
{
	INT i;
	INT erg = OK; /* AK 020692 */

        if (check_equal_2(n,part,last_partition,&erg) == EQUAL)
                return erg; /*AK 180294 */

	erg += b_ks_pa(VECTOR,callocobject(),part);
	erg += m_l_v(n,S_PA_S(part));
	for (i=(INT)0;i<S_I_I(n);i++) 
		M_I_I(1L,S_PA_I(part,i));
	return erg;
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT first_partition(n,part) OP n,part;
/* AK 190587 */
/* die prozedur erzeugt aus der Zahl n die Partition
[n], die erste Partition bezueglich next_partition
bzgl. Dominanzordnung und auch lexikographisch */
/* ok 190587 */ /* AK 060789 V1.0 */ /* AK 261190 V1.1 */
/* AK 200891 V1.3 */
{
	if (S_O_K(n) != INTEGER) /* AK 020692 */
		return error("first_partition:wrong type");
	if (S_I_I(n) <= (INT)0) /* AK 020692 */
		return error("first_partition:input < 1");

	return m_i_pa(n,part); /* AK 020692 */
}



INT next_partition(part,next) OP part,next;
/* AK 060789 V1.0 */ /* AK 300590 V1.1 */ /* AK 200891 V1.3 */
{
	INT erg = OK;
	switch(S_PA_K(part))
	{
	case EXPONENT: return(next_part_EXPONENT(part,next));
	case VECTOR: return(next_part_VECTOR(part,next));
	default: 
		WTO(part,"next_partition"); goto endr_ende;
	};
	ENDR("next_partition");
}
#endif /* PARTTRUE */

INT next_part_VECTOR(part,next) OP part, next;
/* AK 091086 */ /* Nijenhuis ch. 9 */ 
/* AK 060789 V1.0 */ /* AK 120390 V1.1 */ /* AK 200891 V1.3 */
{
#ifdef PARTTRUE
	OP length;
	INT i,j,m,o;
	INT n,k;
	if (S_PA_II(part,(INT)0) > 1)
	/* bsp: 2345 --> 11345 */
	{
		length = callocobject();
		M_I_I(S_PA_LI(part)+1L, length);
		B_KL_PA(VECTOR,length,next);
		M_I_I(1L,S_PA_I(next,(INT)0));
		M_I_I(S_PA_II(part,(INT)0)-1L,S_PA_I(next,1L));
		for (i=2L;i<S_I_I(length);i++)
			M_I_I(S_PA_II(part,(i-1L)),S_PA_I(next,i));
		return OK;
	};
	for (i=(INT)0;i<S_PA_LI(part);i++)
		if (S_PA_II(part,i) > 1L) break;

	if (i == S_PA_LI(part)) return(LASTPARTITION);


	k = S_PA_LI(part) -i; /* restlaenge */
	m = S_PA_II(part,i);
	n = m - 1L ; /* neuer wert in next */
	j = (i + m)  / n;
	o =(i + m)  % n ;

	if (o == (INT)0) j--;
	length = callocobject();
	M_I_I(	j+k, length);

	B_KL_PA(VECTOR,length,next);
	if (o != (INT)0)
	{ 
		M_I_I(o ,S_PA_I(next,(INT)0)); 
		o=1L; 
	};

	for (m=o;m<=j;m++) M_I_I(n, S_PA_I(next,m));

	for (;m<S_I_I(length);m++,i++)
		M_I_I(S_PA_II(part,i+1),S_PA_I(next,m));
	return(OK);
#endif /* PARTTRUE */
}

#ifdef PARTTRUE
INT next_part_EXPONENT(part,next) OP part,next;
/* AK 150888 */ /* AK 060789 V1.0 */ /* AK 121190 V1.1 */ /* AK 200891 V1.3 */
{
	INT l = S_PA_LI(part);
	INT i,index=(INT)0,k;
	INT summe;
	INT value;

	if (S_PA_II(part,(INT)0) == l)
		return(LASTPARTITION);
	/* part = n 0 0 0 0 0 0 ... */

	b_ks_pa(EXPONENT,callocobject(),next);
	m_il_v(l--,S_PA_S(next));
	M_I_I((INT)0,S_PA_I(next,(INT)0));
	for (i=1L;i<=l;i++)
	{
		k = S_PA_II(part,i);
		M_I_I(k,S_PA_I(next,i));
		if (k>(INT)0) {
			index=i++;
			break;
		};
	}
	memcpy(	(char *)S_PA_I(next,i),
		(char *)S_PA_I(part,i),
		(int) (l-i+1L)*sizeof(struct object) );

	summe = S_PA_II(part,(INT)0);

	/* an der stelle index wird der index um eins decrementiert */
	summe = summe + index + 1L;
	M_I_I(S_PA_II(part,index)-1L, S_PA_I(next,index));
	/* nun nach rechts wieder aufbauen */
	for (i=index-1L;i>=(INT)0;i--)
	{
		value = summe / (i+1L);
		M_I_I(value,S_PA_I(next,i));
		summe = summe % (i+1L);

		if (summe == (INT)0) break;
		i = summe;
	}
	return(OK);
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT numberofpart_i(n) OP n;
/* AK  gibt die anzahl der partitionen von n , wobei n INTEGER Typ */
/* AK 060789 V1.0 */ /* AK 120390 V1.1 */ /* AK 200891 V1.3 */
{
	OP zw;
	INT i;
	zw=callocobject();
	numberofpart(n,zw);
	i=S_I_I(zw);
	SYMfreeall(zw);
	return(i);
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT numberofpart(n,x) OP n,x;
/* gibt die anzahl der partitionen von n ,wobei n object */
/* AK 190587 */ /* AK 060789 V1.0 */ /* AK 120390 V1.1 */
/* neu mittels gupta_nm */ /* AK 200891 V1.3 */
{
	OP c,d;
	INT erg = OK; /* AK 041291 */
	if (S_O_K(n) != INTEGER) 
		return WTO("numberofpart",n);
	if (S_I_I(n) <= (INT) 0)
		return error("numberofpart: input <= 0");

	c = callocobject();
	if (S_I_I(n) < (INT)30) 
		{
		erg += last_partition(n,c);
		erg += M_I_I(indexofpart(c)+(INT)1,x);
		}
	else    {
		M_I_I(S_I_I(n)+1L,c);
		erg += gupta_nm_speicher(c,cons_eins,x);
		}
	erg += SYMfreeall(c);
	ENDR("numberofpart");
}

INT indexofpart(part) OP part;
/* gibt die nummer der partition */ /* solange next bis gefunden */
/* AK 190587 */ /* index beginnt mit 0 */
/* AK 060789 V1.0 */ /* AK 260690 V1.1 */ /* AK 200891 V1.3 */
{
	OP b,a;
	INT i=(INT)-1,erg=OK,comperg;
	CTO(PARTITION,"indexofpart",part);

	a = callocobject();

	if (S_PA_K(part) != VECTOR)
		{
		if (S_PA_K(part) != EXPONENT) 
			{
			erg +=  error("indexofpart:wrong kind of part");
			goto endr_ende;
			}
		erg += t_EXPONENT_VECTOR(part,a);
		i = indexofpart(a);
		erg += SYMfreeall(a);
		if (erg != OK) 
			goto endr_ende;
		return i;
		}

	erg += weight_partition(part,a);
	b = callocobject();
	erg += first_partition(a,b);
	i=(INT)0;
	while ((comperg = comp_partition(b,part)) != (INT)0)
		{ 
		  i++; 
		  if (not next(b,b)) 
			{
			debugprint(b);
			erg += error("indexofpart:ERROR");
			}
		};

	erg += SYMfreeall(b);
	erg += SYMfreeall(a);
	if (erg != OK) 
		goto endr_ende;
	return(i);
	ENDR("indexofpart");
}



INT ordcen(part,res) OP part, res;
/* AK 010888 ordnung der konjugiertenklasse ist der index des zentralisators */
/* AK 060789 V1.0 */ /* AK 071289 V1.1 */ /* AK 150591 V1.2 */ 
/* AK 200891 V1.3 */
{
	OP zw = callocobject();
	OP h1 = callocobject();
	OP h2 = callocobject();
	INT erg = OK;
	erg += ordcon(part,h2); 
	erg += weight_partition(part,zw);
	erg += fakul(zw,h1);
	erg += ganzdiv(h1,h2,res);  /* ist ganzzahlig */
	erg += SYMfreeall(zw); 
	erg += SYMfreeall(h2); 
	erg += SYMfreeall(h1); 
	ENDR("ordcen");
}
#endif /* PARTTRUE */


#ifdef TABLEAUXTRUE
#ifdef PARTTRUE
INT m_tableaux_polynom(a,c) OP a, c;
/* AK 250789 */ /* AK 200891 V1.3 */
{
	/* a ist poly of tableaux c wird poly of monom */
	/* AK 060588 */
	OP zeiger;
	INT erg = OK;

	zeiger = a;
	erg += init(POLYNOM,c);
	while( zeiger != NULL)
	{
		OP b = callocobject();
		erg += b_skn_po(callocobject(),callocobject(),NULL,b);
		M_I_I(1L,S_PO_K(b));
		erg += inhalt_tableaux(S_PO_S(zeiger),S_PO_S(b));
		insert(b,c,add_koeff,comp_monomvector_monomvector); 
		zeiger = S_PO_N(zeiger); 
	};
	ENDR("m_tableaux_polynom");
}
#endif /* PARTTRUE */
#endif /* TABLEAUXTRUE */


#ifdef TABLEAUXTRUE
#ifdef PARTTRUE
INT m_part_tableaux(part,alph,res) OP part,alph,res;
/* AK 070588 */
/* erzeugt aus umriss eine liste der tableaus von diesen umriss 
mit eintraegen 1,2,..,alph */
/* ergebnis ist polynom */
/* AK 200891 V1.3 */
{
	return(m_umriss_tableaux(part,alph,res));
}
#endif /* TABLEAUXTRUE */
#endif /* PARTTRUE */


#ifdef TABLEAUXTRUE
#ifdef PARTTRUE
INT m_umriss_tableaux(umriss,alph,res) OP umriss,alph,res;
/* AK 070588 */
/* erzeugt aus umriss eine liste der tableaus von diesen umriss 
	mit eintraegen 1,2,..,alph */
/* ergebnis ist polynom */
/* AK 200891 V1.3 */
{
	OP a,b,c;
	OP start; 
	INT i,j; 
	INT erg = OK; 
	if (S_O_K(umriss) == PARTITION) 
		if (S_I_I(alph) < S_PA_LI(umriss)) return(OK);

	erg += init(SYMLIST,res);

	a = callocobject();
	b = callocobject();
	erg += copy(umriss,a); 
	erg += m_u_t(a,b);
	/* damit haben wird das tablaux */

	j = zeilenanfang(b,0L);
	start = S_T_IJ(b,0L,j);


	/* start ist die linke untere ecke */


	for (i= (INT)0; i< S_I_I(alph); i++)
	{
		M_I_I(i+1L,start); /* initialisieren */
		erg += m060588(b,alph,res);
	}
	erg += SYMfreeall(a);
	erg += SYMfreeall(b);
	ENDR("m_umriss_tableaux");
}
#endif /* PARTTRUE */
#endif /* TABLEAUXTRUE */

#ifdef TABLEAUXTRUE
#ifdef PARTTRUE
static INT m060588(tab,alph,res) OP tab,alph,res;
/* alph ist maximaler eintrag */
/* AK 200891 V1.3 */
{
	OP b,c;
	INT i,j;
	INT grenze;
	INT lasti,lastj;
	for (i=S_T_HI(tab)-1;i>= 0;i--)
	{
		j=zeilenanfang(tab,i);  /* erster erlaubter index */
		if (not emptyp(S_T_IJ(tab,i,j))) break;
	};

	lasti = i;
	/* lasti ist zeile in der letzter eintrag */

	grenze = zeilenende(tab,lasti);

	for (	j=zeilenanfang(tab,lasti);  /* erster erlaubter index */
	j<= grenze; 
	    j++)
		if (emptyp(S_T_IJ(tab,lasti,j))) break;

	lastj = j;
	/* lastj ist letzter eintrag + 1 */


	if (lastj <=   grenze)  { /* d.h. in der zeile kann noch eingetragen
					werden */
		INT m;
		m = S_T_IJI(tab,lasti,lastj-1);
		/* m = der letzte eintrag */

		if (lasti == /* s_t_hi(tab)-1*/ 0L)  /* letzte zeile */
			M_I_I(m,S_T_IJ(tab,lasti,lastj));
			/* rechts anfuegen der gleichen zahl */
		else if (emptyp(S_T_IJ(tab,lasti-1L,lastj)))
			/* bei schief unterhalb leer */
			M_I_I(m,S_T_IJ(tab,lasti,lastj));
			/* rechts anfuegen der gleichen zahl */

		else {
			/* schauen ob unterhalb groesserer eintrag */
			m = 
			    (S_T_IJI(tab,lasti-1L,lastj) >= m ? 
			    S_T_IJI(tab,lasti-1L,lastj)+1 : m);

			if (m > S_I_I(alph)) goto m060588nein;
			/* kann nicht einsetzen */

			M_I_I(m,S_T_IJ(tab,lasti,lastj));
		};
		return(m060588(tab,alph,res));
	};

	/* falls in der zeile nicht mehr eingetragen werden kann */

	i = i+1L; /* neue zeilenzahl */

	if (i < S_T_HI(tab)) {
		j = zeilenanfang(tab,i);
		/* neue spaltenzahl */

		if (not emptyp(s_t_ij(tab,i-1L,j)))
		/* unterhalb der neuen
			position ist ein eintrag */
		{
			if (S_T_IJI(tab,i-1L,j)+1 > S_I_I(alph))
				goto m060588nein;
			M_I_I(s_t_iji(tab,i-1L,j)+1L,s_t_ij(tab,i,j));
			return(m060588(tab,alph,res));
		}
		else M_I_I(1L,s_t_ij(tab,i,j));
	};
	/* nun sind wir am ende */
	b = callocobject();
	c = callocobject();
	copy(tab,b);
	b_s_po(b,c);
	insert(c,res,NULL,NULL);
	/* jetzt muss versucht werden das naechste tableaux 
	zu bekommen */
m060588nein:
	if (m060588b(tab,alph) == TRUE) m060588(tab,alph,res);
	/* d.h noch nicht letztes tableaux */
	return(OK);
}
#endif /* PARTTRUE */
#endif /* TABLEAUXTRUE */


#ifdef TABLEAUXTRUE
#ifdef PARTTRUE
static INT m060588b(tab,alph) OP tab,alph;
/* es wird versucht das naechste tableaux zu bekommen */
/* AK 200891 V1.3 */
{
	INT i,j;
	INT lastj = zeilenanfang(tab,0L);
	for (i=s_t_hi(tab)-1; i>=0 ;i--)
		for (j= s_t_li(tab)-1L;j >= (INT)0; j--)
			if (not emptyp(s_t_ij(tab,i,j)))
				/* es gibt einen eintrag */
				if (i == 0L  && j == lastj)
					return(FALSE);
					/* wir sind am ende */
				else if (s_t_iji(tab,i,j) < S_I_I(alph))
				{
					inc(s_t_ij(tab,i,j));
					return(TRUE);
				}
				else 
				{
					freeself(s_t_ij(tab,i,j));
					return(m060588b(tab,alph));
				}
	return(FALSE);
}
#endif /* PARTTRUE */
#endif /* TABLEAUXTRUE */


INT t_augpart_part(a,b) OP a,b;
/* AK 150988 */ /* AK 060789 V1.0 */ /* AK 170190 V1.1 */
/* AK 200891 V1.3 */
{
#ifdef PARTTRUE
	INT i,s;
	copy(a,b);
	C_O_K(b,PARTITION);
	for (i=(INT)0;i<S_PA_LI(b);i++)
	{ 
		M_I_I(S_PA_II(b,i)-i,s_pa_i(b,i));
		if (S_PA_II(b,i)==(INT)0) s++; 
	}
	if (s != (INT)0) /* d.h. 0 am anfang */
	{
		OP nv = callocobject();
		m_il_v(S_PA_LI(b)-s,nv);
		for (i=(INT)0; i<S_V_LI(nv); i++)
			M_I_I(S_PA_II(b,i+s),S_V_I(nv,i));
		SYMfreeall(S_PA_S(b)); 
		C_PA_S(b,nv);
	}
	return(OK);
#endif /* PARTTRUE */
}

#ifdef PARTTRUE
INT comp_partition(a,b) OP a,b;
/* AK 110488*/ /* AK 060789 V1.0 */ /* AK 191289 V1.1 */
/* AK 070891 V1.3 */
{
	INT i;
	INT erg;
	char *ac, *bc;
	if ((S_O_K(a) != PARTITION) || (S_O_K(b) != PARTITION) )
		return WTT("comp_partition",a,b);
		
	if (S_PA_K(a) != S_PA_K(b)) 
		return error("comp_partition:different kind of partitions");

	if (S_PA_K(a) == VECTOR )
		{
#ifdef __alpha
		erg =  comp_integervector(S_PA_S(a), S_PA_S(b));
		goto cpende;
#endif /* __alpha */
		ac = (char *) S_V_S(S_PA_S(a));
		bc = (char *) S_V_S(S_PA_S(b));
		if (S_PA_LI(a) == S_PA_LI(b))
			{
			erg =  (INT)memcmp(ac,bc,
				( sizeof(struct object) * S_PA_LI(a) ));
			goto cpende;
			}
		if (S_PA_LI(a) < S_PA_LI(b))
			{
			erg = (INT) memcmp(ac,bc,
				(sizeof(struct object) * S_PA_LI(a) ));
			if (erg == (INT)0)  erg = (INT)-1;
			goto cpende;
			}
		if (S_PA_LI(a) > S_PA_LI(b))
			{
			erg = (INT)memcmp(ac,bc,
				(sizeof(struct object) * S_PA_LI(b) ));
			if (erg == (INT)0)  erg = (INT)1;
			goto cpende;
			}

		}
	else if (S_PA_K(a) == EXPONENT)
		{
		for (	i=(INT)0; i<S_PA_LI(a); i++)
			{
			if (i >=  S_PA_LI(b) ) 
				{
				if (S_PA_II(a,i) != (INT)0) 
					{
					erg = (INT)1;
					goto cpende;
					}
				}
			else if (S_PA_II(a,i) > S_PA_II(b,i)) 
				{
				erg = (INT)1;
				goto cpende;
				}
			else if (S_PA_II(a,i) < S_PA_II(b,i)) 
				{
				erg = (INT)-1;
				goto cpende;
				}
			}
		
		for (	; i<S_PA_LI(b); i++)
			if (S_PA_II(b,i) != (INT)0) 
				{
				erg = (INT)-1; 
				goto cpende;
				}
		}
	erg = (INT)0; goto cpende;
cpende:
	return erg;
}



INT part_ende()
	{
	INT i;
	INT erg = OK;
	for (i=pa_index; i>=(INT)0;i--)
		{
		SYM_free(pa_sp[i]);
		mem_counter_part--; /* AK 100893 */
		}
	if (pa_sp != NULL)
		{
		erg += SYM_free(pa_sp);
		pa_sp = NULL; /* AK 160893 */
		pa_index = -1L;
		}
	if (mem_counter_part != (INT)0) /* AK 100893 */
		{
		fprintf(stderr,"mem_counter_part = %ld\n",mem_counter_part);
		erg += error("memory problem with partitions");
		}
	return erg;
	}

INT freeself_partition(a) OP a;
/* AK 110488 */ /* AK 060789 V1.0 */ /* AK 211189 V1.1 */
/* AK 120691 V1.2 */ /* AK 070891 V1.3 */
{
	OBJECTSELF d;
	INT erg = OK;

	if (pa_sp == NULL) /* AK 111091 */
		{
		pa_sp = (struct partition **)SYM_malloc(
				PASIZE * sizeof(struct partition *));
		}
	if (S_O_K(a) == CHARPARTITION)
		SYM_free(S_PA_S(a));
	else if (S_PA_K(a) == FROBENIUS)
		erg += SYMfreeall(S_PA_S(a));
	else
		{
		if (S_PA_S(a) != NULL)
			erg += SYMfreeall(S_PA_S(a));
		}
	d = S_O_S(a); 

	if (pa_index+1 < PASIZE) /* AK 111091 */
		pa_sp[++pa_index]=d.ob_partition;
	else
		{
		SYM_free(d.ob_partition); 
		mem_counter_part--; /* AK 100893 */
		}
	C_O_K(a,EMPTY);
	ENDR("freeself_partition");
}

INT copy_partition(a,b) OP a,b;
/* AK 060789 V1.0 */ /* AK 191289 V1.1 */ /* AK 070891 V1.3 */
{
	INT erg = OK;
	erg += b_ks_pa(S_PA_K(a),callocobject(),b);
	erg += m_il_v(S_PA_LI(a),S_PA_S(b));
	memcpy(
		(char *) S_V_S(S_PA_S(b)),
		(char *) S_V_S(S_PA_S(a)),
		(int)(S_PA_LI(a)*sizeof(struct object)) );
	C_O_K(b,S_O_K(a)); /* copy of AUG_PART e.g. */
	ENDR("copy_partition");
}


INT tex_partition(part) OP part;
/* AK 101187 */ 
/* output of a PARTITIONobject in format for TeX */
/* AK 060789 V1.0 */ /* AK 170190 V1.1 */
/* AK 070291 V1.2 texout for output */ /* AK 070891 V1.3 */
{
	INT erg = OK;
	fprintf(texout,"\\ $ "); /* uebergang in math-mode */
	erg += fprint(texout,part);
	texposition = (INT)0;
	fprintf(texout," $\\ "); /* ende math-mode */
	ENDR("tex_partition");
}




static struct partition * callocpartition()
/* AK 060789 V1.0 */ /* AK 170889 malloc statt calloc */ /* AK 170190 V1.1 */
/* AK 070891 V1.3 */
{
	struct  partition *erg;


	if (pa_index > -1L)
		erg = pa_sp[pa_index--];
	else 
		{
		erg = (struct partition *) SYM_malloc(sizeof(struct partition));
		mem_counter_part++; /* AK 100893 */
		}

	
	if (erg == NULL) 
		error("callocpartition: no memory");

	return(erg);
}



INT inversordcen(part,ergeb) OP part, ergeb;
/* AK inverse der ordnung des zentralisator der sn der durch part
bestimmt ist 210387 */
/* AK 060789 V1.0 */
/* AK 131189 langzahl arithmetik */
/* AK 170190 V1.1 */ /* AK 070891 V1.3 */
{
	INT i;
	INT erg = OK; /* AK 090692 */
	OP sp = callocobject();

	m_i_i(1L,ergeb);
	M_I_I(1L,sp);
	for (i=(INT)0; i<S_PA_LI(part);i++)
	{ 
		if (i>(INT)0)
		{ 
			if (S_PA_II(part,i) == S_PA_II(part,(i-1L)))
			{ INC_INTEGER(sp); 
			  erg += mult_apply(sp,ergeb); 
			}
			else M_I_I(1L,sp); 
		};
		erg += mult_apply(S_PA_I(part,i),ergeb);
	};


	erg += invers_apply(ergeb);
	erg += SYMfreeall(sp);
	ENDR("inversordcen");
}




INT ordcon(part,res) OP part, res;
/* AK ordnug der konjugiertenklasse der sn die durch part
bestimmt ist 200387  nur bei INTEGER ergebnis */
/* AK 060789 mit beliebigen ergebnis */
/* AK 060789 V1.0 */ /* AK 081289 V1.1 */ /* AK 070891 V1.3 */
{
	INT i;
	INT erg = OK;
	OP ergebnis,sp;
	OP  h1;
	if (S_O_K(part) == CHARPARTITION) /* AK 170593 */
		return ordcon_char(part,res);
	if (S_O_K(part) != PARTITION)
		return WTO("ordcon",part);
	if (S_PA_K(part) != VECTOR)
		return ERROR;

	h1 = callocobject();
	sp=callocobject();
	M_I_I(1L,sp);
	ergebnis=callocobject();
	M_I_I(1L,ergebnis);
	if (not EMPTYP(res)) 
		if (S_O_K(res) != INTEGER) 
			erg += freeself(res);
	for (i=(INT)0; i<S_PA_LI(part);i++)
	{
		if (i>(INT)0)
		{ 
			if (S_PA_II(part,i) == S_PA_II(part,(i-1L)))
			{
				INC_INTEGER(sp);
				erg += mult_apply_integer(sp,ergebnis);
			}
			else M_I_I(1L,sp);
		};
		erg += mult_apply_integer(S_PA_I(part,i),ergebnis);
	};
	erg += weight_partition(part,h1); 
	erg += fakul(h1,sp);
	erg += SYMfreeall(h1); 
	erg += ganzdiv(sp,ergebnis,res); /* diese division ist ganzzahlig */

	erg += SYMfreeall(sp); 
	erg += SYMfreeall(ergebnis); 
	ENDR("ordcon");
}



static INT ordcon_char(part,res) OP part, res;
{
	INT i;
	INT erg = OK;
	OP ergebnis,sp;
	OP  h1,h2;
	if (S_O_K(part) != CHARPARTITION) /* AK 170593 */
		return ERROR;
	if (S_PA_K(part) != VECTOR)
		return ERROR;

	h1 = callocobject();
	h2 = callocobject(); 
	sp=callocobject();
	M_I_I(1L,sp);
	ergebnis=callocobject();
	M_I_I(1L,ergebnis);
	if (not EMPTYP(res)) 
		if (S_O_K(res) != INTEGER) 
			erg += freeself(res);
	for (i=(INT)0; i<S_PA_CL(part);i++)
	{
		if (i>(INT)0)
		{ 
			if (S_PA_CII(part,i) == S_PA_CII(part,(i-1L)))
			{
				INC_INTEGER(sp);
				erg += mult_apply_integer(sp,ergebnis);
			}
			else M_I_I(1L,sp);
		};
		M_I_I(S_PA_CII(part,i),h2); /* AK 170593 */
		erg += mult_apply_integer(h2,ergebnis);
	};
	erg += weight_partition(part,h1); 
	erg += fakul(h1,sp);
		erg += SYMfreeall(h1); 
	erg += ganzdiv(sp,ergebnis,res); /* diese division ist ganzzahlig */

	erg += SYMfreeall(sp); 
	erg += SYMfreeall(ergebnis); 

	erg += SYMfreeall(h2);
	ENDR("ordcon_char");
}




INT m_v_pa(vec,part) OP vec, part;
/* erzeugt aus einem vector eine partition
durch sortieren und vergessen der nullen. */
/* AK 060789 V1.0 */ /* AK 240490 V1.1 */ /* AK 150591 V1.2 */ 
/* AK 070891 V1.3 */
{
	INT i=(INT)0,j, erg=OK;
	OP self;
	OP zz;

        if (check_equal_2(vec,part,m_v_pa,&erg) == EQUAL)
                return erg;

	self = callocobject(); 
	erg += copy(vec,self); 
	erg += sort(self);

	if (S_V_II(self,(INT)0) < (INT)0) { 
		erg += SYMfreeall(self);
		return error("m_v_pa: negativ entries"); 
		}

	while (S_V_II(self,i) == (INT)0)  	/* eintraege = 0 werden ueberlesen */
		if (i++ == (S_V_LI(self) - 1L)) 
			{ 
			erg += SYMfreeall(self); 
			goto mvpa_ende;  /* nur nullen */
			}

	
/* die laenge der ergebnis-partition vectorlaenge - anzahl der nullen   */
	if ((S_V_LI(self)-i) == 1L)  /* AK 121093 */
		{
		j = S_V_II(self,i);
		erg += SYMfreeall(self);
		self = callocobject();
		m_il_v(1L,self);
		M_I_I(j,S_V_I(self,(INT)0));
		}
	else	{
		M_I_I(S_V_LI(vec) - i,S_V_L(self));
		for (j=0;j<S_V_LI(self);j++)
			M_I_I(S_V_II(self,i+j),S_V_I(self,j));
		}

	erg +=  b_ks_pa(VECTOR,self,part);	/* part ist das ergebnis */
mvpa_ende:
	ENDR("m_v_pa");
}

INT m_int_pa(i,result) INT i; OP result;
{
	OP c;
	INT erg = OK;
	if (i < 0)
		{
		erg += error("negative INT in m_int_pa");
		goto endr_ende;
		}
	c=callocobject();
	erg += M_I_I(i,c);
	erg += b_i_pa(c,result);
	ENDR("m_int_pa");
}

INT m_i_pa(i,result) OP i,result;
/* AK 280890 V1.1 */ /* AK 150591 V1.2 */ /* AK 070891 V1.3 */
	{
	INT erg = OK;
	OP c;
	CTO(INTEGER,"m_i_pa",i);
	if (S_I_I(i) < 0)
		{
		erg += error("INTEGER < 0 in m_i_pa");
		goto endr_ende;
		}
	c = callocobject();
	M_I_I(S_I_I(i),c);
	erg += b_i_pa(c,result);
	ENDR("m_i_pa");
	}


INT b_i_pa(integer,ergebnis) OP integer,ergebnis;
/* AK 140687 */ /* Bsp: 5 --> [5] */
/* AK 060789 V1.0 */ /* AK 280890 V1.1 */ /* AK 070891 V1.3 */
{
	INT erg = OK;
	CTO(INTEGER,"b_i_pa",integer);
	if (S_I_I(integer) < 0)
		{
		erg += error("INTEGER < 0 in b_i_pa");
		goto endr_ende;
		}
	
	erg += b_ks_pa(VECTOR,callocobject(),ergebnis);
	erg += b_o_v(integer,S_PA_S(ergebnis));
	ENDR("b_i_pa");
}



INT m_ks_pa(kind,self,ergebnis) OP self,ergebnis; OBJECTKIND kind;
/* make_kind.self_partition */
/* AK 300590 V1.1 */ /* AK 070891 V1.3 */
{
	OP s = NULL;
	INT erg = OK;
	if (self != NULL) { 
		s = callocobject();
		erg += copy(self,s); 
		}
	erg += b_ks_pa(kind,s,ergebnis);
	ENDR("m_ks_pa");
}


INT b_ks_pa(kind,self,c) OP self,c; OBJECTKIND kind;
/* build_kind_self_partition */ /* AK 060789 V1.0 */ /* AK 300590 V1.1 */
/* AK 200891 V1.3 */
{
	OBJECTSELF d;
	INT erg = OK;
	
	d.ob_partition = callocpartition();
	erg += b_ks_o(PARTITION, d, c);
	C_PA_K(c,kind); 
	C_PA_S(c,self); 
	ENDR("b_ks_pa");
}


INT m_kl_pa(a,b,c) OBJECTKIND a; OP b,c;
/* AK 060789 V1.0 */ /* AK 280890 V1.1 */ /* AK 200891 V1.3 */
{
	return(b_ks_pa(a,callocobject(),c) || m_l_v(b,S_PA_S(c)));
}
INT b_kl_pa(a,b,c) OBJECTKIND a; OP b,c;
/* AK 180893 */
{
	INT erg = OK;
	erg += b_ks_pa(a,callocobject(),c) ;
	erg += b_l_v(b,S_PA_S(c));
	ENDR("b_kl_pa");
}


INT dec_partition(a) OP a;
/* AK 060789 V1.0 */ /* AK 261190 V1.1 */ /* AK 200891 V1.3 */
{
	INT i;
	INT erg = OK;
	CTO(PARTITION,"dec_partition",a);
	if (S_PA_K(a) == VECTOR) 
		{
		erg += dec_vector(S_PA_S(a));
		}
	else if (S_PA_K(a) == EXPONENT)
		{
		for(i=S_PA_LI(a)-1L;i>=(INT)0;i--)
			if (S_PA_II(a,i) > (INT)0) 
				erg += m_i_i(S_PA_II(a,i)-1L,S_PA_I(a,i));	
		}
	else
		{
		erg += error("dec_partition:wrong kind of part");
		} 
	ENDR("dec_partition");
}

INT lastof_partition(a,b) OP a,b;
/* AK 060789 V1.0 */ /* AK 261190 V1.1 */ /* AK 200891 V1.3 */
{
	return(lastof_vector(S_PA_S(a),b));
}



INT length_partition(a,b) OP a,b;
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
{
	
	if (S_O_K(a) != PARTITION) return ERROR; /* AK 170692 */
	if (S_PA_K(a) == VECTOR) return length_vector(S_PA_S(a),b);
	if (S_PA_K(a) == EXPONENT) return sum(S_PA_S(a),b);
	return ERROR;
}



INT weight_partition(a,b) OP a,b;
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
{
	INT i ,res=(INT)0;
	if (S_O_K(a) == CHARPARTITION)
		if (S_PA_K(a) == VECTOR) {
			for (i=S_PA_CL(a)-1L;i>=(INT)0;i--) res += S_PA_CII(a,i);
			return(M_I_I(res,b)); 
			}
	if (S_O_K(a) != PARTITION) 
		return ERROR; /* AK 170692 */
	if (S_PA_K(a) == VECTOR) {
		for (i=S_PA_LI(a)-1L;i>=(INT)0;i--) res += S_PA_II(a,i);
		return(M_I_I(res,b)); 
		}
	else if (S_PA_K(a) == EXPONENT) {
		for (i=S_PA_LI(a)-1L;i>=(INT)0;i--) res += (i+1) * S_PA_II(a,i);
		return(M_I_I(res,b)); 
		}
	else return error("weight_partition: wrong kind of part");
}



INT scan_partition(c) OP c;
/* AK zum einlesen einer partition von der standardeingabe */
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 250291 V1.2 */
/* AK 200891 V1.3 */
{
	INT erg=OK;
spa:
	erg += b_ks_pa(VECTOR,callocobject(),c);
	erg += printeingabe("input of partition as increasing vector");
	erg += scan(INTEGERVECTOR,S_PA_S(c));
	if (partitionp(c) != TRUE) /* AK 170692 */
		{
		erg += printeingabe("you did not enter a partition");
		erg += freeself(c);
		goto spa;
		}
	ENDR("scan_partition");
}



OP s_pa_s(a) OP a;
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
	{ 
	OBJECTSELF c; 
	c = s_o_s(a); 
	return(c.ob_partition->pa_self); 
	}

OBJECTKIND s_pa_k(a) OP a;
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
	{ 
	OBJECTSELF c; 
	c = s_o_s(a); 
	return(c.ob_partition->pa_kind); 
	}

OP s_pa_i(a,i) OP a; INT i;
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
	{ 
	return(s_v_i(s_pa_s(a),i)); 
	}

INT s_pa_ii(a,i) OP a; INT i;
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
	{ 
	return(s_v_ii(s_pa_s(a),i)); 
	}

OP s_pa_l(a) OP a;
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
	{ 
	return(s_v_l(s_pa_s(a))); 
	}

INT s_pa_li(a) OP a;
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
	{ 
	return(s_v_li(s_pa_s(a))); 
	}

INT c_pa_k(a,b) OP a; OBJECTKIND b;
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
	{ 
	OBJECTSELF c; 
	c = s_o_s(a); 
	c.ob_partition->pa_kind = b; 
	return(OK); 
	}

INT c_pa_s(a,b) OP a,b;
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
	{ 
	OBJECTSELF c; 
	c = s_o_s(a); 
	c.ob_partition->pa_self = b; 
	return(OK); 
	}


INT neqparts_partition(a) OP a;
/* test whether only different parts in the
partition a AK 071189 */
/* AK 181289 V1.1 */ /* AK 200891 V1.3 */
{
	INT i;
	for (i=S_PA_LI(a)-2L;i >= (INT)0; i--)
		if (S_PA_II(a,i) == S_PA_II(a,i+1) ) return(FALSE);
	return(TRUE);
}



INT objectread_partition(filename,part) OP part; FILE *filename;
/* AK 291086 zum einlesen einer partition von einem file */
/* AK 060789 V1.0 */ /* AK 181289 V1.1 */ /* AK 200891 V1.3 */
{
	INT kind;
	INT erg = OK;
	fscanf(filename,"%ld",&kind);
	erg += b_ks_pa((OBJECTKIND)kind, callocobject(),part);
	erg += objectread(filename,S_PA_S(part));
	ENDR("objectread_partition");
}

INT objectwrite_partition(filename,part) FILE *filename; OP part;
/* AK 291086 */ /* zum schreiben einer partition auf einen file */
/* AK 060789 V1.0 */ /* AK 200690 V1.1 */ /* AK 200891 V1.3 */
{
	INT erg = OK;
	fprintf(filename,"%ld\n",(INT)PARTITION);
	fprintf(filename,"%ld\n",(INT)S_PA_K(part));
	erg += objectwrite(filename,S_PA_S(part));
	ENDR("objectwrite_partition");
}


INT t_VECTOR_EXPONENT(von,nach) OP von,nach;
/* A.K. 190588 wandelt eine Partition in der Darstellung
1223 um in die Darstellung
1^1 2^2 3^1 4^0 .. 8^0
d.h in den Vektor 12100000 */
/* AK 060789 V1.0 */ /* AK 200690 V1.1 */ /* AK 200891 V1.3 */
{
	INT i;
	OP l;
	INT erg = OK; 
	CE2(von,nach,t_VECTOR_EXPONENT);
	if (EMPTYP(von) ) /* AK 140892 */
		{
		erg += b_ks_pa(EXPONENT,callocobject(),nach);
		erg += m_il_nv(1L,S_PA_S(nach));
		goto endr_ende;
		}
	l=callocobject();
	erg += weight(von,l);
	erg += b_ks_pa(EXPONENT,callocobject(),nach);
	erg += b_l_nv(l,S_PA_S(nach));

	for (i=(INT)0;i<S_PA_LI(von);i++)
		erg += inc(S_V_I(S_PA_S(nach),S_PA_II(von,i) -1L));

	ENDR("t_VECTOR_EXPONENT");
}


INT t_EXPONENT_VECTOR(a,b) OP a,b;
/* AK 160988 */ /* AK 060789 V1.0 */ /* AK 200690 V1.1 */ /* AK 200891 V1.3 */
{

	INT i,j,z=(INT)0;
	INT erg = OK;
	OP l;
	CE2(a,b,t_EXPONENT_VECTOR);
	l = callocobject();
	j=(INT)0; for (i=(INT)0;i<S_PA_LI(a);i++) j += S_PA_II(a,i); M_I_I(j,l);
	erg += b_ks_pa(VECTOR,callocobject(),b);
	erg += b_l_v(l,S_PA_S(b));
	for (i=(INT)0;i<S_PA_LI(a);i++)
		for (j=(INT)0;j<S_PA_II(a,i);j++)
		{
			M_I_I(i+1L,S_PA_I(b,z));
			z++;
		};
	ENDR("t_EXPONENT_VECTOR");
}


INT test_part()
/* AK 200690 V1.1 */ /* AK 130691 V1.2 */ /* AK 200891 V1.3 */
{
	OP a = callocobject();
	OP b = callocobject();
	OP c = callocobject();
	printf("test_part:scan(a) "); 
	scan(PARTITION,a);
	printf("test_part:println(a) "); println(a);
	printf("test_part:ordcon(a,b) "); ordcon(a,b); println(b);
	printf("test_part:conjugate(a,b) "); conjugate(a,b); println(b);
	printf("test_part:append(a,b,c) "); append(a,b,c); println(c);
	printf("test_part:add(a,b,c) "); add(a,b,c); println(c);
	printf("test_part:next(c,c) "); next(c,c); println(c);
	printf("test_part:ordcen(c,b) "); ordcen(c,b); println(b);
	printf("test_part:dimension_partition(c,b) "); 
	dimension_partition(c,b); println(b);
	printf("test_part:hook_length(c,(INT)0,(INT)0,b) "); 
	hook_length(c,(INT)0,(INT)0,b); println(b);
	printf("test_part:partitionp(c) "); 
	if (partitionp(c) == TRUE) printf("is partition\n");
	m_i_i((INT)10,c);
	printf("test_part:makevectorofpart((INT)10,b) "); 
	makevectorofpart(c,b); println(b);
	printf("test_part:random_partition((INT)10,b) "); 
	random_partition(c,b); println(b);
	printf("test_part:dec(b) "); dec(b); println(b);
	printf("test_part:length(b,c) "); length(b,c); println(c);
	printf("test_part:weight(b,c) "); weight(b,c); println(c);
	printf("test_part:t_VECTOR_EXPONENT(b,b) "); 
	t_VECTOR_EXPONENT(b,b); println(b);
	printf("test_part:dec(b) "); dec(b); println(b);
	printf("test_part:length(b,c) "); length(b,c); println(c);
	printf("test_part:weight(b,c) "); weight(b,c); println(c);
	printf("test_part:conjugate(b,c) "); conjugate(b,c); println(c);
	printf("test_part:dimension_partition(c,b) "); 
	dimension_partition(c,b); println(b);
	printf("test_part:hook_length(c,(INT)0,(INT)0,b) "); 
	hook_length(c,(INT)0,(INT)0,b); println(b);
	SYMfreeall(a); SYMfreeall(b); SYMfreeall(c); return OK;
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT makevectorofpart(n,vec) OP n,vec;
/* AK 200587 */
/* erzeugt einen vector der in der i-ten position die i-te partition von n 
enthaelt ordnung bezueglich nextpartition */
/* AK 060789 V1.0 */ /* AK 081289 V1.1 */ /* AK 130691 V1.2 */
/* AK 200891 V1.3 */
{
	INT i,erg =OK;
	OP l;

	if (S_O_K(n) != INTEGER) /* AK 020692 */
		{
		cast_apply_integer(n); /* AK 280494 */
		if (S_O_K(n) != INTEGER) 
			return WTO(n,"makevectorofpart");
		}
	if (S_I_I(n) < (INT)0) /* AK 020692 */
		return error("makevectorofpart:input < 0");

	if (S_I_I(n) == (INT)0)
		return m_il_v((INT)0,vec);

	l=callocobject();

	erg += numberofpart(n,l);
	erg += b_l_v(l,vec);
	erg += first_partition(n,S_V_I(vec,(INT)0));
	for (i=1L;i<S_V_LI(vec);i++)
		erg += next_part_VECTOR(S_V_I(vec,(i-1L)),S_V_I(vec,i));
	ENDR("makevectorofpart");
}



INT weight_augpart(a,b) OP a,b;
/* AK 160988 */ /* AK 060789 V1.0 */ /* AK 120390 V1.1 */ /* AK 130691 V1.2 */
/* AK 200891 V1.3 */
{
	INT i,k=(INT)0;
	if (S_O_K(a) != AUG_PART) return ERROR;
	for (i=S_PA_LI(a)-1L;i>=(INT)0;i--) k = k + S_PA_II(a,i) - i;

	return M_I_I(k,b);
}



INT contain_comp_part(a,b) OP a,b;
/* true if a sub b */
{
	INT i,j;
	if (S_PA_LI(a) > S_PA_LI(b)) return FALSE;
	for (i=0;i<S_PA_LI(a);i++)
		{
		if (S_PA_II(a,S_PA_LI(a)-1-i) > S_PA_II(b,S_PA_LI(b)-1-i)) return FALSE;
		}
	return TRUE;
}

INT dom_comp_part(a,b) OP a,b;
/* returns 0 on equal
           1 if a bigger according dominance
           -1     smaller
           NONCOMPARABLE if not comparable */
/* AK 140591 V1.2 */ /* AK 200891 V1.3 */
	{
	INT i,j,s1,s2;
	INT l,erg = (INT)0;	
	l = (S_PA_LI(a) > S_PA_LI(b)) ?  S_PA_LI(a) : S_PA_LI(b) ;
	/* l is the length of the longer partition */
	for (i=(INT)0; i<l ; i++)
		/* all partial sums */
		{
		s1 = s2 = (INT)0;
		for (j=(INT)0;j<=i;j++)
			{
			if (j < S_PA_LI(a)) s1 += S_PA_II(a,S_PA_LI(a)-1L-j);
			if (j < S_PA_LI(b)) s2 += S_PA_II(b,S_PA_LI(b)-1L-j);
			}
	/* s1 is partialsum of a 
           s2 is partialsum of b */
		if (erg == (INT)0) 
			{
			if (s1 > s2) erg = (INT)1;
			if (s1 < s2) erg = (INT)-1;
			}
		else if ( erg == 1L )
			{
			if (s1 < s2) return NONCOMPARABLE; /* not comparable */
			}
		else if ( erg == -1L )
			{
			if (s1 > s2) return NONCOMPARABLE; /* not comparable */
			}
		else
			error("dom_comp_part: wrong internal erg");
		}
	return erg;
	}




INT even_partition(a,b) OP a,b;
{
	OP c;
	INT erg;
	c = callocobject();
	weight(a,c);
	sub(c,S_PA_L(a),c);
	erg = even(c);
	SYMfreeall(c);
	return erg;
}



INT random_partition(n,b) OP n,b;
/* new random partition nijnhuis wilf p.76 */
/* AK 151092 also for longint */
{
	OP nlast,k,z,multi,p,d,m,i,isum,is,i1,j;
	INT erg = OK;

	CTO(INTEGER,"random_partition",n);
	if (S_I_I(n) <= (INT)0) 
		{
		erg +=  error("random_partition: n <= 0");
		goto endr_ende;
		}
	multi=callocobject(); p=callocobject(); z=callocobject();
	nlast=callocobject(); m=callocobject(); i=callocobject();
	k=callocobject(); j=callocobject(); isum=callocobject();
	is=callocobject(); i1=callocobject(); d=callocobject();
	erg += m_i_i((INT)0,nlast);
	erg += m_l_nv(n,multi);
	erg += m_l_v(n,p);
	l10: if (le(n,nlast)) goto l30;
	l20: erg += m_i_i(1L,S_V_I(p,(INT)0));
	erg += add(nlast,cons_eins,m);
	erg += copy(n,nlast);
	if (eq(n,cons_eins)) goto l30;
	for(copy(m,i); le(i,n); inc(i))
		{
		erg += m_i_i((INT)0,isum);
		for (m_i_i(1L,d); le(d,i); inc(d) )
			{
			erg += m_i_i((INT)0,is);
			erg += copy(i,i1);
	l24:		erg += sub(i1,d,i1);
			if (lt(i1,cons_null) ) goto l22;
			if (eq(i1,cons_null) ) goto l25;
			erg += add_apply(S_V_I(p,S_I_I(i1)-1L),is);
			goto l24;
	l25:		erg += inc(is);
	l22:		erg += mult_apply(d,is);
			erg += add_apply(is,isum);
			}
		erg += ganzdiv(isum,i,S_V_I(p,S_I_I(i)-1L));
		}
	l30: 	erg += copy(n,m);
	erg += m_i_i((INT)0,k);
	l40: 	erg += mult(m,S_V_I(p,S_I_I(m)-1L),d);
		erg += random_integer(z,cons_eins,d);
		erg += m_i_i((INT)0,d);
	l110:	erg += inc(d);
	l60:	erg += copy(m,i1);
		erg += m_i_i((INT)0,j);
	l150:	erg += inc(j);
	l70:	erg += sub(i1,d,i1);
	l80:	if (lt(i1,cons_null)) goto l110;
		if (eq(i1,cons_null)) goto l90;
	erg += mult(d,S_V_I(p,S_I_I(i1)-1),is);
	erg += sub(z,is,z);
	l130:	if (le(z,cons_null)) goto l145;
		goto l150;
	l90:	erg += sub(z,d,z);
	l100:	if (le(z,cons_null)) goto l145;
		goto l110;
	l145:	erg += add_apply(j,S_V_I(multi,S_I_I(d)-1L));
		erg += add_apply(j,k);
	l160:	erg += copy(i1,m);
	l170:	if (neq(m,cons_null)) goto l40;

	erg+=SYMfreeall(z); 
	erg+=SYMfreeall(nlast); 
	erg+=SYMfreeall(k); 
	erg+=SYMfreeall(m);
	erg+=SYMfreeall(p); 
	erg+=SYMfreeall(i); 
	erg+=SYMfreeall(i1); 
	erg+=SYMfreeall(j);
	erg+=SYMfreeall(is); 
	erg+=SYMfreeall(isum);

	erg += b_ks_pa(EXPONENT,multi,d); /* do not free multi */
	erg += t_EXPONENT_VECTOR(d,b);
	erg += SYMfreeall(d);
	ENDR("random_partition");
}


INT t_VECTOR_FROB(a,b) OP a,b;
/* AK 101292 */
{
	INT i,j;
	INT erg = OK;
	OP c;
	erg += b_ks_pa(FROBENIUS,callocobject(),b);
	erg += m_il_v(2L,S_PA_S(b));
	for (i=(INT)0, j=S_PA_LI(a)-1L;S_PA_II(a,j) > i; i++,j--) ;
	erg += m_il_v(i,S_V_I(S_PA_S(b),(INT)0));
	erg += m_il_v(i,S_V_I(S_PA_S(b),1L));
	c = callocobject();
	erg += conjugate(a,c);
	for (j=(INT)0;j<S_V_LI(S_V_I(S_PA_S(b),(INT)0));j++)
		{
		erg += m_i_i(S_PA_II(a,S_PA_LI(a)-1L-j)-1L-j, S_V_I(S_V_I(S_PA_S(b),(INT)0),j));
		erg += m_i_i(S_PA_II(c,S_PA_LI(c)-1L-j)-1L-j, S_V_I(S_V_I(S_PA_S(b),1L),j));
		}
	erg += SYMfreeall(c);
	ENDR("t_VECTOR_FROB");
}


	INT t_PARTITION_CHARPARTITION(a,b) OP a,b;
	/* only for internal use */
{
	INT erg = OK;
	if (a == b) 
		return ERROR;
	if (S_PA_K(a) == FROBENIUS)
		return ERROR;
	erg += freeself(b);
	erg += b_ks_pa(S_PA_K(a), NULL, b);
	erg += t_INTVECTOR_UCHAR(S_PA_S(a), & S_PA_S(b));
	C_O_K(b,CHARPARTITION);
	return erg;
}


	INT c_PARTITION_CHARPARTITION(a) OP a;
	/* only for internal use */
	/* AK 170593 */
{
	INT erg = OK;
	OP c = callocobject();
	*c = *a;
	C_O_K(a,EMPTY);
	erg += t_PARTITION_CHARPARTITION(c,a);
	erg += SYMfreeall(c);
	return erg;
}

	INT c_CHARPARTITION_PARTITION(a) OP a;
	/* only for internal use */
	/* AK 170593 */
{
	INT erg = OK;
	OP c = callocobject();
	*c = *a;
	C_O_K(a,EMPTY);
	erg += t_CHARPARTITION_PARTITION(c,a);
	erg += SYMfreeall(c);
	return erg;
}

	INT t_CHARPARTITION_PARTITION(a,b) OP a,b;
	/* only for internal use */
{
	INT erg = OK;
	if (a == b) 
		return ERROR;
	if (S_PA_K(a) == FROBENIUS)
		return ERROR;
	erg += freeself(b);
	erg += b_ks_pa(S_PA_K(a), callocobject(), b);
	erg += t_UCHAR_INTVECTOR(S_PA_S(a),  S_PA_S(b));
	return erg;
}


INT t_PARTITION_AUGPART(a,b) OP a,b;
/* AK 170593 */
{
	INT erg = OK;
	INT i;
	if (a==b) 
		return ERROR;
	if (S_O_K(a) != PARTITION)
		return ERROR;
	if (S_PA_K(a) != VECTOR)
		return ERROR;
	erg += copy(a,b);
	for (i=(INT)0;i<S_PA_LI(a);i++)
		M_I_I(S_PA_II(a,i)+i,S_PA_I(b,i));
	C_O_K(b,AUG_PART);
	ENDR("t_PARTITION_AUGPART");
}

INT c_CHARAUGPART_CHARPARTITION(a) OP a;
/* AK 170593 */
{
	INT erg = OK;
	INT i;
	if (S_O_K(a) != CHAR_AUG_PART)
		return ERROR;
	if (S_PA_K(a) != VECTOR)
		return ERROR;
	for (i=(INT)0;i<S_PA_CL(a);i++)
		 S_PA_CII(a,i) = S_PA_CII(a,i)-i;
	C_O_K(a,CHARPARTITION);
	return erg;
}

INT c_CHARPARTITION_CHARAUGPART(a) OP a;
/* AK 170593 */
{
	INT erg = OK;
	INT i;
	if (S_O_K(a) != CHARPARTITION)
		return ERROR;
	if (S_PA_K(a) != VECTOR)
		return ERROR;
	for (i=(INT)0;i<S_PA_CL(a);i++)
		 S_PA_CII(a,i) = S_PA_CII(a,i)+i;
	C_O_K(a,CHAR_AUG_PART);
	return erg;
}
INT c_AUGPART_PARTITION(a) OP a;
/* AK 170593 */
{
	INT erg = OK;
	INT i;
	if (S_O_K(a) != AUG_PART)
		return ERROR;
	if (S_PA_K(a) != VECTOR)
		return ERROR;
	for (i=(INT)0;i<S_PA_LI(a);i++)
		M_I_I(S_PA_II(a,i)-i, S_PA_I(a,i));
	C_O_K(a,PARTITION);
	return erg;
}

INT c_PARTITION_AUGPART(a) OP a;
/* AK 170593 */
{
	INT erg = OK;
	INT i;
	if (S_O_K(a) != PARTITION)
		return ERROR;
	if (S_PA_K(a) != VECTOR)
		return ERROR;
	for (i=(INT)0;i<S_PA_LI(a);i++)
		M_I_I(S_PA_II(a,i)+i, S_PA_I(a,i));
	C_O_K(a,AUG_PART);
	return erg;
}
#endif /* PARTTRUE */

#ifdef PARTTRUE

struct axelclaude {
	int  nbl, nbc, contrib,rang;
	int *pdl, *pdc;
	int *mat;
	int *ligne_mat; 
};


INT row_column_matrices(a,c,e) OP a,c,e;
/* AK 131093 CP 031293 */
{
	int i;
	OP d;
	INT erg = OK;
	struct axelclaude aa;

	if (S_O_K(a) == PARTITION)
		{
	if (S_PA_K(a) != VECTOR)
		return error("row_column_matrices requires VECTOR partitions");
		a = S_PA_S(a);
		}
	if (S_O_K(c) == PARTITION)
		{
	if (S_PA_K(c) != VECTOR)
		return error("row_column_matrices requires VECTOR partitions");
		c = S_PA_S(c);
		}

	if ((S_O_K(a) != VECTOR) || (S_O_K(c) != VECTOR))
		{
		WTT("row_column_matrices",a,c);
		goto endr_ende;
		}

	d = callocobject();
	aa.nbl=S_V_LI(a)+1; 
	aa.nbc=S_V_LI(c)+1;
	aa.pdl = (int *) SYM_calloc(aa.nbl, sizeof(int));
	aa.pdc = (int *) SYM_calloc(aa.nbc, sizeof(int));
	aa.ligne_mat = (int *) SYM_calloc(aa.nbc, sizeof(int));
	aa.mat = (int *) SYM_calloc(aa.nbc * aa.nbl, sizeof(int));

	for(i=0;i<S_V_LI(a);i++)  aa.pdl[i+1]= S_V_II(a,i);
	for(i=0;i<S_V_LI(c);i++)  aa.pdc[i+1]= S_V_II(c,i);
	erg += m_ilih_m(aa.nbc-1,aa.nbl-1,d);
	erg += m_il_v((INT)0,e);
	aa.contrib=aa.pdl[1];
	aa.rang=1;
	repartir(&aa,aa.rang,aa.contrib,aa.pdc,aa.ligne_mat,aa.nbc,d,e);
	SYM_free(aa.pdl);
	SYM_free(aa.pdc);
	SYM_free(aa.ligne_mat);
	SYM_free(aa.mat);
	erg += SYMfreeall(d);
	ENDR("row_column_matrices");
}

/******************************************************************
 *          passage de aaaaaa a abbbbbb                           *
 ******************************************************************/
static int remplir(contrib,pdc,v,d,l) int contrib, l, pdc[], v[];
{
	int i, x;
	for(i=d;i<=l;i++) v[i] = 0;
	i = l; 
	x = contrib;
	while(x>0) {
		if(i==d-1) return 0;
		if(x>=pdc[i]) { 
			v[i]=pdc[i]; 
			x -= pdc[i--];
		}
		else { 
			v[i] = x; 
			x = 0;
		}
	}
	return 1;
}

/**********************************************************************
 *        partitions avec contraintes                                 *
 **********************************************************************/
static int repartir(aa,rang,contrib,pdc,v,lv,dd,e)  OP dd,e;
	int rang, contrib, lv, pdc[], v[];
	struct axelclaude *aa;
{
	int d,l,x,i;
	int *w, *pdcv;
	pdcv = (int *) SYM_calloc(lv,sizeof(int));
	w = (int *) SYM_calloc(lv,sizeof(int));
	d=1; 
	l=lv-1;
	while(1) {
		remplir(contrib,pdc,v,d,l);
		utiliser(aa,rang,v,lv,dd,e);
		if(rang<aa->nbl-1) {
			for(i=1;i<=l;i++) pdcv[i]=pdc[i]-v[i];
			repartir(aa,rang+1,aa->pdl[rang+1],pdcv,w,lv,dd,e);
		}
		i=l-1; 
		contrib = v[l];
		while(i>0) if(v[i]==pdc[i]) contrib += v[i--];
		else if(contrib==0) contrib=v[i--]; 
		else break;
		if(i>0) { 
			v[i]++; 
			contrib--; 
			d=i+1; 
			continue; 
		}
		else break;
	}
	SYM_free(pdcv);
	SYM_free(w);
}

/*******************************************************************
 *         exploitation d'une ligne construite                     *
 *******************************************************************/
static int utiliser(aa,rang,v,lv,d,e)  OP d,e; struct axelclaude *aa; int v[], lv;
{
	int i, j;
	/* for(i=1;i<lv;i++) aa->mat[rang][i]=v[i]; */
	for(i=1;i<lv;i++) aa->mat[(rang*aa->nbc) +i]=v[i];

	if(rang==aa->nbl-1) {
		inc(e);
		for(i=1;i<aa->nbl;i++) {
		for(j=1;j<lv;j++)   
			M_I_I(aa->mat[(i*aa->nbc) +j],S_M_IJ(d,i-1,j-1) );
		}
		copy(d,S_V_I(e,S_V_LI(e)-1));

	}
}


INT sscan_partition(t,a) OP a; char *t;
/* AK 050194 to read partition from string
	format [1,2,3,23,23,33]
*/
{
	INT i,n,erg = OK;

	char *v,*w;
	v = t;
	while (*v == ' ') v++;
	if (*v != '[')
		{erg = ERROR; goto spe;}
	w = v; n = (INT)1;
	/* now we count the number of parts */
	w++;
	while (*w != ']')
		{
		if (*w == ',') n++;
		else if (not SYM_isdigit(*w))
			{erg = ERROR; goto spe;}
		w++;
		}
	/* n is the number of parts */
	b_ks_pa(VECTOR,callocobject(),a);
	m_il_v(n,S_PA_S(a));
	w = v;
	w++;
	for (i=(INT)0; i<n; i++)
		{
		erg += sscan(w,INTEGER,S_PA_I(a,i));
		if (erg != OK) goto spe;

		while (SYM_isdigit(*w)) w++;
		w++;
		}
	spe:
	if (erg != OK)
		fprintf(stderr,"string = %s\n",t);
	ENDR("sscan_partition");
}


INT cast_apply_part(a) OP a;
/* AK 280294 */
{
	INT erg = OK;
	switch(S_O_K(a))
		{
		case INTEGER:
			erg += m_i_pa(a,a);
			break;
		case VECTOR:
			erg += m_v_pa(a,a);
			break;
		default:
			printobjectkind(a);
			erg += error("cast_apply_part: can not cast");
			break;
		}
	ENDR("cast_apply_part");
}

INT equal_parts(a,b) OP a,b;
/* return TRUE if PART a has >= b equal parts */
{
	INT erg = OK;
	INT i,j=0L,k=0L;
	CTO( PARTITION,"equal_parts",a);
	CTO( INTEGER,"equal_parts",b);
	if (S_PA_K(a) != VECTOR)
		{
		erg +=  error("equal_parts: partition object not VECTOR kind");
		goto endr_ende;
		}
	if (S_I_I(b) <= (INT)0) 
		{
		erg +=  error("equal_parts: integer object not bigger 0");
		goto endr_ende;
		}

	for (i=0L;i<S_PA_LI(a);i++)
		{
		if (S_PA_II(a,i) == k) j++;
		else { k = S_PA_II(a,i); j= 1L; }
		if (j == S_I_I(b)) return TRUE;
		}
	return FALSE;
	ENDR("equal_parts");
}
INT q_core(a,b,d) OP a,b,d;
/* AK 301095 */
{
	INT erg = OK,i,j;
	OP e;
	CTO(PARTITION,"q_core",a);
	CTO(INTEGER,"q_core",b);

	e = callocobject();
	erg += copy(a,d);
aa:
	for (i=0L;i<S_PA_LI(d);i++)
	for (j=0L;j<S_PA_II(d,S_PA_LI(d)-1-i);j++)
		{
		erg += hook_length(d,i,j,e);
		if (EQ(e,b))
			{ erg += remove_hook(d,i,j,d); 
			  if (EMPTYP(d)) goto bb;
			  goto aa; }
		}
bb:
	erg += SYMfreeall(e);
	ENDR("q_core");
}


INT remove_hook(a,i,j,c) OP a,c; INT i,j;
/* AK 301095 */
{
	INT erg =OK,k;
	OP d;
	CTO (PARTITION ,"remove_hook",a);
               
        if (S_PA_K(a) != VECTOR)
                return ERROR;
	if (i >= S_PA_LI(a))
                return copy(a,c);
        if (j >= S_PA_II(a,S_PA_LI(a)-1L-i))
                return copy(a,c);
	d = callocobject();
	erg += copy(S_PA_S(a),d);
	m_i_i(j,S_V_I(d,S_PA_LI(a)-i-1));
	for (k=i+1L; k<S_PA_LI(a); k++)
                if (S_PA_II(a,S_PA_LI(a)-1L-k) -1L >= j) 
			{
			erg += dec(S_V_I(d,S_PA_LI(a)-1L-k));
			erg += copy(S_V_I(d,S_PA_LI(a)-1L-k),S_V_I(d,S_PA_LI(a)-k));
			}
		else    {

			m_i_i(j,S_V_I(d,S_PA_LI(a)-k));

			break;
			} 
	if (k == S_PA_LI(a))
		m_i_i(j,S_V_I(d,0L)); 
	erg += m_v_pa(d,c);
	erg += SYMfreeall(d);
	ENDR("remove_hook");
  
}

INT p_hook_diagramm(a,b,c) OP a,b,c;
/* AK 010295 */
{
	INT erg=OK,i,j,k,l;
	CTO(INTEGER,"p_hook_diagramm",b);
	CTO(PARTITION,"p_hook_diagramm",a);
	if (S_I_I(b) < (INT) 0) 
		{
		erg += error("p_hook_diagramm: second parameter < 0");
		goto ee;
		}
	erg += hook_diagramm(a,c);
	if (S_I_I(b) == 0) goto ee;
	for (i=0L;i<S_M_HI(c);i++)
	for (j=0L;j<S_M_LI(c);j++)
		if (S_M_IJI(c,i,j) == (INT)0) C_O_K(S_M_IJ(c,i,j),EMPTY);
		else {
			k = S_I_I(b); 
			l = 1;
			while  (S_M_IJI(c,i,j) % k == (INT)0) 
				{l++;k *= S_I_I(b);}
			M_I_I(l-1,S_M_IJ(c,i,j));
			}
		
ee:
	ENDR("p_hook_diagramm");
}
#endif /* PARTTRUE */

#ifdef PARTTRUE
INT odd_to_strict_part(a,b) OP a,b;
/* AK 020196 */
{
	INT erg = OK;
	OP c = callocobject();
	OP d = callocobject();
	INT i,j,k,l;
	erg += t_VECTOR_EXPONENT(a,c);
	erg += weight(a,d);
	erg += m_il_nv(S_I_I(d),d);
	l = 0;
	for (i=0;i<S_PA_LI(c);i++)
		{
		if (S_PA_II(c,i) != 0)
			{
			j=1;k=S_PA_II(c,i);
	aa:
			if (k % 2) {
				erg += m_i_i((i+1)*j,S_V_I(d,l));
				l++;
				}
			k /=2 ;
			j *= 2;
			if (j <= S_PA_II(c,i)) goto aa;
			}
		}
	erg += m_v_pa(d,b);
	erg += SYMfreeall(c);
	erg += SYMfreeall(d);
	ENDR("odd_to_strict_part");
}

INT strict_to_odd_part(a,b) OP a,b;
/* AK 020196 */
{
	INT erg = OK;
	INT i,k,l=0,j;
	OP c,d;
	c = callocobject();
	erg += weight(a,c);
	erg += m_il_nv(S_I_I(c),c);
	for (i=0;i<S_PA_LI(a);i++)
		{
		k = S_PA_II(a,i);
		if ((k%2) == 1)
			{
			erg += m_i_i(k,S_V_I(c,l)); l++;
			}
		else	{
			j=4;
	aa:
			if ((k%j) == 0) {j *= 2; goto aa;}
			j /= 2;  /* j ist die hoechste 2er potenz die passt */
			k = k/j;
			for (;j>0;j--)
				{
				erg += m_i_i(k,S_V_I(c,l)); l++;
				}
			}
		}
	erg += m_v_pa(c,b);
	erg += SYMfreeall(c);
	ENDR("strict_to_odd_part");
}
#endif /* PARTTRUE */
#ifdef PARTTRUE
#endif /* PARTTRUE */

#undef callocobject
