/*****************************************************************************/
/* Including needed files */
/**************************/

/* C include files */
/* #include <stdarg.h>    //  Already included */

/* SYMMETRICA macros and prototypes */
#include "def.h"
#include "macro.h"



/*****************************************************************************
 debugging messages: 
 If DO_DEBUG is defined, you can get output of debugging information in 
 MuPAD by specifying a MuPAD function , which sets do_debug to 1
 
 There seems to be no reason to undefine this feature
 *****************************************************************************/

#define DO_DEBUG 

#ifdef DO_DEBUG

INT do_debug=0;

// Write a debug message in printf style:

void DEBUG(char *f, ...) {
  if (!do_debug) return;
  va_list ap;
  va_start(ap,f);
  MFprintf(f, ap);
  va_end(ap);
}


// Write the content of a MuPAD variable:
void DEBUG(MTcell mo) {
  if (!do_debug) return;
  MFout(mo);
}

// Write the content of a SYMMETRICA variable:
void DEBUG(OP so) {
  if (!do_debug) return;
//   char str[1024];
//   sprint(str,so);
//   MFputs(str);
  print(so);
}  

#else

#define DEBUG(str)

#endif


/*****************************************************************************
 *****************************************************************************
  Some small help functions:
 *****************************************************************************
 ****************************************************************************/

/*****************************************************************************
 SYMMETRICA: build_object(a,res): "copies" object a to res, and deletes a
 ****************************************************************************/

inline void b_o(OP a, OP res) 
{
  swap(a,res);
  SYMfreeall(a);
}


/*****************************************************************************
  MuPAD: I often need Mupad expressions of the form ["_mult",a,b].
  With the following macro, I just have to call 
    mupad_calc("_mult",a,b,result);
  (Where a, b and result are MTcells.)
 ****************************************************************************/

inline MTcell mupad_calc( char* calc, MTcell a, MTcell b)
{
  return MFnewExpr(3, MFident(calc),a,b);
}

/*****************************************************************************
 *****************************************************************************
 Converting MuPAD Objects to SYMMETRICA objects:

   SYM_object= SYM_m2s(mupad_object, TYPE,...)

 The function returns NULL, if an error has occured.
 You have to specify the wanted SYMMETRICA type. For some types, you also need
 to specify further types for subelements.
 In MuPAD, you can "index" a vector or an integer. Otherwise MuPAD would 
 complain, if you want to calc with vectors. So in general, you can write
 <anything>[3]   instead of 3,    and   <anything>[3,2] instead of [3,2].

 It is usual, to write s[3,2], if [3,2] specifies a SCHUR base element,
 m[3,2], if it specifies a MONOMIAL base element, and so on.

 Following SYMMETRICA types are supported (so far):
 
 OBJECTKIND:     expected MuPAD format:  comment

 EMPTY                            (reserved)
 INTEGER         3, 2/3,                 supports fractions, too. (But then,
                                         the resulting OBJECTKIND is BRUCH) 
 PARTITION       [3,2], s[3,2]           (is a VECTOR of INTEGERS)
                                         in SYMMETRICA, a partition is stored
                                         in increasing order, eg. 23
 SKEWPARTITION   [[3,2],[2,1]]           A partition is allowed, too
 PERMUTATION     [3,1,2]                 (is a VECTOR of INTEGERS)
                                         vector of the images (starting by 1)

 MATRIX                           not yet implemented
 TABLEAUX                         not yes implemented

 SCHUR           2 s[3,2] - s[2,1] + s[2]      (is a POLYNOM of PARTITIONS)
 POW_SYM         2 s[3,2] - s[2,1] + s[2]      (is a POLYNOM of PARTITIONS)
 SCHUBERT        2 X[2,1,3] + X[1,3,2]   (is a POLYNOM of PERMUTATIONS)

 MONOPOLY        2 x^3 - 3 x                   (is a POLYNOM of INTEGERS)

 POLYNOM,<exp>                                 (is a SYMLIST of MONOMS)
 MONOM,<exp>     2 <anything>^<exp> or 2 <exp> the base of the MONOM is lost

 SYMLIST,<elem>  <elem> + <elem>               just a sum of elems
 VECTOR,<elem>   <anything>[<elem>,<elem>] or [<elem>,<elem>] 

 ( Following types specify symmetric functions over different bases:
   POW_SYM	symmetric powersum
   HOM_SYM	complete homogenous symmetric functions
   MONOMIAL	momomial symmetric functions
   ELM_SYM	elementary symmetric functions
 )

 *****************************************************************************
 ****************************************************************************/

OP SYM_m2s( MTcell mo, ... /*OBJECTKINDS*/ );


// internal functions, which are called recursively:
static OP SYM_m2s_internal( MTcell mo, va_list ap /*OBJECTKINDS*/ );
static OP SYM_m2s_internal2( MTcell mo, ... /*OBJECTKINDS*/ );

// internal flags: To store information between recursive calls
static int SYM_m2s_VECTOR_reverse; // Should I reverse a vector (for partitions)


// This function should be called:
OP SYM_m2s( MTcell mo, ...)
{
  OP so;
  va_list ap;
  va_start(ap, mo); 
  DEBUG("Converting from MuPAD to SYMMETRICA...\n");

  // Default values for the flags:
  SYM_m2s_VECTOR_reverse=0;     

  // call the recursive function:
  so=SYM_m2s_internal(mo, ap);

  DEBUG("\nConversion finished\n");
  va_end(ap);

  return so;
}


// This fuction is needed, to give new OBJECTKINDS
// The remaining objectkinds can be given as va_list. To indicate this case,
// just give an objectkind EMPTY in front of the va_list:
OP SYM_m2s_internal2( MTcell mo, ... /*OBJECTKINDS*/ )
{
  OP so;
  va_list ap;
  va_start(ap, mo); 

  so=SYM_m2s_internal(mo, ap);

  va_end(ap);
  return so;
}


// This function does the real conversion:
OP SYM_m2s_internal( MTcell mo, va_list ap /*OBJECTKINDS*/ )
{
  OBJECTKIND knd=va_arg(ap, OBJECTKIND);

  // An EMPTY as OBJECTKIND signifies, that the next parameter is a va_list.
  while (knd==EMPTY) {
    // the next argument is a va_list itself. 
    ap=va_arg(ap, va_list);
    knd=va_arg(ap, OBJECTKIND);
  }

  switch ( knd ) {

  case INTEGER: case BRUCH: 
    { // recognized formats: 3, p[3], 2/3,  p[2,3]
      OP so;
      switch(MFdom(mo)) 
	{
	case DOM_INT:   {        		// eg. 3
	  OP so=callocobject();
	  m_i_i(MFlong(mo), so);
	  DEBUG(so); DEBUG(" ");
	  return so;
	}
	case DOM_APM: {				// LONGINT
	  DEBUG("LONGINT.");
	  // This is an easy but inefficient solution:
	  char *str=MFexpr2text(mo);
 	  sscan(str, LONGINT, so);
	  MFcfree(str);
 	  DEBUG(so); DEBUG(" ");
 	  return so;
	} 
	case DOM_RAT: {  			// eg. 2/3
	  DEBUG("RATIONAL.");
	  OP so_o=SYM_m2s_internal2(MFratNum(mo), INTEGER);
	  DEBUG(".");
	  if (!so_o) return NULL;
	  DEBUG(".");
	  OP so_u=SYM_m2s_internal2(MFratDen(mo), INTEGER);
	  if (!so_u) { SYMfreeall(so_o); return NULL; }
	  
	  so=callocobject();
	  b_ou_b(so_o, so_u, so);
	  DEBUG(so); DEBUG(" ");
	  return so;
	} 
	case DOM_EXPR: { // This must be last case!!
	  if( MFisExpr(mo,"_index") && MFnopsExpr(mo)==3) { // eg. p[3]
	    so=SYM_m2s_internal2(MFgetExpr(&mo,2),INTEGER);
	    return so;
	  }
	  // else error (i.e. no break and go into default part)
	} 
	default:
	  {                              		// error 
	    DEBUG("(SYM) Integer expected. Instead, I got:"); DEBUG(mo); 
	    return NULL;
	  }
	};
    }
    
  case PARTITION:
    { // VECTOR of INTEGERs in decreasing order 
      // (i.e. we have to reverse the vector)
      DEBUG("PARTITION... ");

      int help=SYM_m2s_VECTOR_reverse;    SYM_m2s_VECTOR_reverse=1;
      OP so_vector=SYM_m2s_internal2(mo,VECTOR,INTEGER);
      if (!so_vector) return NULL;
      SYM_m2s_VECTOR_reverse=help;

      OP so=callocobject();
      b_ks_pa(VECTOR, so_vector, so);

      DEBUG("PARTITION finished: ");  DEBUG(so);  DEBUG(" ");
      return so;
    }

  case SKEWPARTITION:
    { // List of two PARTITIONs, eg: [[3,2,1],[2,1]]
      // Does not support indexed list: <anything>[[3,2,1],[2,1]] (needed?)
      DEBUG("SKEWPARTITION... ");
      OP so;

      if (MFisList(mo) && MFnopsList(mo)==2 &&
	  !MFisInt(MFgetList(&mo,1))) { // is really a SKEWPARTITION
	OP so_big  =SYM_m2s_internal2(MFgetList(&mo,0),PARTITION);
	if (!so_big) return NULL;
	OP so_small=SYM_m2s_internal2(MFgetList(&mo,1),PARTITION);
	if (!so_small) { SYMfreeall(so_big); return NULL; }

	so=callocobject();
	b_gk_spa(so_big, so_small, so);
      } else {             // try PARTITION
	so=SYM_m2s_internal2(mo,PARTITION);
	if (!so) return NULL;
      }

      DEBUG("SKEWPARTITION finished: ");  DEBUG(so);  DEBUG(" ");
      return so;
    }

  case PERMUTATION:
    {  // VECTOR of INTEGERs (the images) (starting with 1)
      DEBUG("PERMUTATION... ");

      OP so_vector=SYM_m2s_internal2(mo,VECTOR,INTEGER);
      if (!so_vector) return NULL;

      OP so=callocobject();
      b_ks_p(VECTOR, so_vector, so);

      DEBUG("PERMUTATION finished: ");  DEBUG(so);  DEBUG(" ");
      return so;
    }

  case MATRIX:
    {
      DEBUG("MATRIX not yet implemented.");
      return NULL;
    }

  case TABLEAUX:
    {
      DEBUG("TABLEAUX not yet implemented.");
      return NULL;
    }

  case SCHUR: 
  case POW_SYM: 
  case HOM_SYM:
  case MONOMIAL:
  case ELM_SYM:
    { // POLYNOM of PARTITIONS
      DEBUG("Symm. Fkt... ");

      OP so=SYM_m2s_internal2(mo,POLYNOM,PARTITION);
      if (!so) return NULL;
      C_O_K(so,knd);

      DEBUG("Symm. Fkt. finished: ");  DEBUG(so);  DEBUG(" ");
      return so;
    }

  case SCHUBERT: 
    { // POLYNOM of PERMUTATIONS
      DEBUG("SCHUBERT... ");

      OP so=SYM_m2s_internal2(mo,POLYNOM,PERMUTATION);
      if (!so) return NULL;
      C_O_K(so,SCHUBERT);

      DEBUG("SCHUBERT finished: ");  DEBUG(so);  DEBUG(" ");
      return so;
    }
      
  case MONOPOLY:
    { // POLYNOM of INTEGER
      DEBUG("MONOPOLY... ");

      OP so=SYM_m2s_internal2(mo,POLYNOM,INTEGER);
      if (!so) return NULL;
      C_O_K(so,MONOPOLY);

      DEBUG("SCHUR finished: ");  DEBUG(so);  DEBUG(" ");
      return so;
    }
  
  case POLYNOM: //needs Type for the monom-base (coefficient is always BRUCH)
    { // LIST of MONOMS
      DEBUG("POLYNOM... ");

      OP so=SYM_m2s_internal2(mo,SYMLIST,MONOM,EMPTY,ap);
      if (!so) return NULL;
      C_O_K(so,POLYNOM);

      DEBUG("POLYNOM finished: ");  DEBUG(so);  DEBUG(" ");
      return so;
    }

  case MONOM: // needs type of base (coefficient is always BRUCH)
    { // ["_mult", base, exp] or base (exp=1)
      DEBUG("MONOM... ");

      MTcell mo_coeff,mo_base, mo_exp;

      if(MFisExpr(mo, "_mult") &&  MFnopsExpr(mo)==3) { //   base * coeff 
	// In all examples I tried, the coefficient was the second part of the
	// multiplication. (Perhaps, because it is an integer)
	// Perhaps one should try the opposite, if this fails.
	mo_base=MFgetExpr(&mo,1);
	mo_coeff=MFgetExpr(&mo,2);
      } else {                           // base (coeff== 1 or -1)
// 	mo_coeff=(MFspec(mo) & MINUS_BIT) ? MVone_ : MVone;
	mo_coeff=MVone;
	mo_base=mo;
      }

      if(MFisExpr(mo_base,"_power") && MFnopsExpr(mo)==3)  { // <anything>^exp
	mo_exp=MFgetExpr(&mo_base,2);
      } else {                          // exp (no base given)
	mo_exp=mo_base; 
      }

      OP so_exp=SYM_m2s_internal(mo_exp, ap);
      if (!so_exp) return 0; // trying with exchanged coeff and base?
      OP so_coeff=SYM_m2s_internal2(mo_coeff, INTEGER);
      if (!so_coeff) { SYMfreeall(so_exp); return 0; }
      
      OP so=callocobject();
      b_sk_mo(so_exp, so_coeff, so);

      DEBUG("MONOM finished: ");  DEBUG(so);  DEBUG(" ");
      return so;
    }

  case SYMLIST: 
    { // // is a sums of elements; needs type of the elements
      DEBUG("LIST...");
      OP so, so_this, so_next, so_elem;

      if(MFisExpr(mo,"_plus")) {  //  elem + elem +...
	int i, len;
	so=callocobject(); init(SYMLIST,so);
	len=MFnopsList(mo);
	for ( i=1, so_this=so; i<len; i++, so_this=so_next)  {
	  so_elem=SYM_m2s_internal(MFgetList(&mo,i),ap);
	  if (!so_elem) { SYMfreeall(so); return NULL; }
	  so_next=(i<len-1)? callocobject():(OP)NULL;
	  b_sn_l( so_elem, so_next, so_this);
	}
      } else {                                         // monom (one element)
	so_elem=SYM_m2s_internal(mo,ap);
	if (!so_elem) return NULL;
	so=callocobject(); 
	b_sn_l( so_elem, (OP)NULL, so);
      }

      DEBUG("LIST finished: ");  DEBUG(so);  DEBUG(" ");
      return so;
    }

  case VECTOR: // needs type of elements
    {  //  [a,b,c], s[a,b,c] (i.e: [<_index>, <something>, a,b,c]
      DEBUG("VECTOR... ");
      INT len,i,start;
      
      if (MFisList(mo)) {               // eg. [3,2]
	len=MFnopsList(mo);
	start=0;
      } 
      else if(MFisExpr(mo,"_index") && MFnopsExpr(mo)>=3) { // eg. s[3,2]
	len=MFnopsExpr(mo)-2;
	start=2;
      } 
      else { 
	DEBUG("(SYM) Vector expected. Instead, I got:"); DEBUG(mo); 
	return NULL;
      }

      OP so, so_elem;
      so=callocobject();
      m_il_v(len,so);
      for (i=0;i<len; i++) {  
	so_elem=SYM_m2s_internal( MFop(mo,i+start), ap);
	if (!so_elem) { SYMfreeall(so); return NULL; }
	b_o( so_elem, S_V_I(so, (SYM_m2s_VECTOR_reverse?len-1-i:i)) );
      }
      
      DEBUG("VECTOR finished: ");  DEBUG(so);  DEBUG(" ");
      return so;
    }
  }
  DEBUG("ERROR: UNKNOWN TYPE: %ld\n",knd);
  return NULL;
}


/*****************************************************************************
 *****************************************************************************
 Converting SYMMETRICA Objects into MuPAD objects (deletes SYMMETRICA object):

   SYM_object= SYM_m2s(mupad_object, TYPE,...)

 The function returns NULL, if an error has occured.
 MuPAD vectors (and so also partitions and Permutations) get indexed by the
 context. For example, if a partition specifies a schur base element, 
 I write s[3,2] instead of [3,2].
 
 SYMMETRICA       MuPAD (example)

 EMPTY            ' '
 INTEGER           3 
 BRUCH             2/3

 PARTITION         [3,2]            In SYMMETRICA, the partition is stored in
                                    increasing order. If the partition belongs
				    to a special polynom (eg. SCHUR) it gets
				    indexed (eg. s[3,2])
 SKEWPARTITION             not yet implemented
 PERMUTATION       [2,1,3]          vector of the images (starting by 1)

 MATRIX                              
 TABLEAUX                           MATRIX with some empty entries

 SCHUR           2 s[3,2] - s[2,1] + s[2]      (is a POLYNOM of PARTITIONS)
 MONOMIAL        2 m[3,2] - m[2,1] + m[2]      (is a POLYNOM of PARTITIONS)
 POW_SYM         2 p[3,2] - p[2,1] + p[2]      (is a POLYNOM of PARTITIONS)
 SCHUBERT        2 perm[2,1,3] + perm[1,3,2]   (is a POLYNOM of PERMUTATIONS)

 MONOPOLY        2 x^3 - 3 x                   (is a POLYNOM of INTEGERS)

 POLYNOM,<exp>                                 (is a SYMLIST of MONOMS)
 MONOM,<exp>     2 <anything>^<exp> or 2 <exp> the base of the MONOM is lost

 SYMLIST,<elem>  <elem> + <elem>               just a sum of elems
 VECTOR,<elem>   [3,2,3]
 
 *****************************************************************************
 ****************************************************************************/

MTcell SYM_s2m( OP so);

// internal function, which is called recursively:
MTcell SYM_s2m_internal( OP so );


// internal flags: To store information between recursive calls
/*
  Vectors are used for different purposes:
  1) A partition. Write just [3,2].
  2) A permutation.          perm[2,1,3]
  2) As an element of Sn, over a given base (e.g. schur polynoms: s[3,2])
  
  During the recursive calls of SYM_s2m_internal, we'll get an idea, what type
  of partitions we will need, and store this information in 
    SYM_s2m_partition_type
  If we then have to convert a partition, we look into this variable, and 
  according to the value, we can convert the partitions into the right format.
  Eg. if we convert a SHUR polynom, we want to encode the  corresponding 
  partitions should be as s[3,2]. So we will store a "s" in the static 
  variable SYM_s2m_VECTOR_index: 
  */

static char const* SYM_s2m_VECTOR_index;
static int         SYM_s2m_VECTOR_reverse;
static int         SYM_s2m_MONOM_base;

// Some values for the flags:
static char const*const  SYM_s2m_VECTOR_index_nothing="";
static char const*const  SYM_s2m_VECTOR_index_s="s";
static char const*const  SYM_s2m_VECTOR_index_p="p";
static char const*const  SYM_s2m_VECTOR_index_h="h";
static char const*const  SYM_s2m_VECTOR_index_m="m";
static char const*const  SYM_s2m_VECTOR_index_e="e";
static char const*const  SYM_s2m_VECTOR_index_perm="perm";
static char const*const  SYM_s2m_VECTOR_index_X="X";

static const int SYM_s2m_MONOM_base_nothing=0;
static const int SYM_s2m_MONOM_base_q=1;


// This function should be called:
MTcell SYM_s2m( OP so )
{
  MTcell mo;                       // The resulting SYMMETRICA object
  DEBUG("Converting from SYMMETRICA to MuPAD...\n");

  SYM_s2m_VECTOR_index=SYM_s2m_VECTOR_index_nothing;
  SYM_s2m_VECTOR_reverse=0;
  SYM_s2m_MONOM_base=SYM_s2m_MONOM_base_nothing;

  mo=SYM_s2m_internal(so);

  DEBUG("\nConversion finished\n");
  SYMfreeall(so);
  return mo;
}


// This function does the real work:
MTcell SYM_s2m_internal( OP so )
{
  MTcell mo; 
  OBJECTKIND knd=S_O_K(so);
  switch ( knd ) {
  case EMPTY:
    {
      DEBUG("EMPTY ");
      mo=MFident(" ");
      return mo;
    }
  case INTEGER:
    {
      mo=MFlong(s_i_i(so));

      DEBUG("%ld ", MFlong(mo));
      return mo;
    }
  case LONGINT:
    {
      DEBUG("LONGINT... ");
      // This is an easy but inefficient solution:
      char buffer[256];  /* I hope, this is long enough! 
                            (I don't see any possibility to check!) */
      sprint(buffer,so);
      mo=MFtext2expr(buffer);
      
      DEBUG("LONGINT finished: ");  DEBUG(mo);
      return mo;
    }
  case BRUCH:
    {
      DEBUG("BRUCH... ");

      MTcell mo_o=SYM_s2m_internal(s_b_o(so));
      if (!mo_o) return NULL;
      MTcell mo_u=SYM_s2m_internal(s_b_u(so));
      if (!mo_u) { /*MMT_free(mo_o);*/ return NULL; }

      mo=MFrat(mo_o, mo_u);

      DEBUG("BRUCH finished: ");  DEBUG(mo);
      return mo;
    }

  case PARTITION:
    {      // the Partition type must be of type VECTOR!
      DEBUG("PARTITION... ");

      OP v=s_pa_s(so);
      int store=SYM_s2m_VECTOR_reverse; SYM_s2m_VECTOR_reverse=1;
      mo=SYM_s2m_internal(v);
      SYM_s2m_VECTOR_reverse=store;
      if(!mo) return NULL;

      DEBUG("PARTITION finished: ");
      DEBUG(mo);
      return mo;
    }

  case PERMUTATION:
    {      // the PERMUTATION type must be VECTOR!
      DEBUG("PERMUTATION... ");

      OP v=s_p_s(so);
      mo=SYM_s2m_internal(v);
      if (!mo) return NULL;

      DEBUG("PERMUTATION finished: ");
      DEBUG(mo);
      return mo;
    }

  case MATRIX:
    {
      DEBUG("MATRIX... ");

      // Convert to List of rows
      INT h,l,i,j;
      MTcell mo_listlist, mo_list, mo_elem;

      h=s_m_hi(so);
      l=s_m_li(so);

      if(h>0 && l>0) {
	mo_listlist=MFnewList( h );
	for (i=0;i<h; i++) {
	  mo_list=MFnewList( l );
	  for (j=0;j<l; j++) {
	    mo_elem=SYM_s2m_internal(S_M_IJ(so, i, j));
	    if(!mo_elem) { /*MFfree(mo_list); MFfree(mo_listlist)*/return NULL; }
	    MFsetList( &mo_list, j, mo_elem );
	  }
	  MFsig(mo_list);  // List finished
	  MFsetList( &mo_listlist, i, mo_list );
	}
	MFsig(mo_listlist);  // List finished
      } else { // special case empty array:
	h=l=1;	
	mo_listlist=MFnewList( 1 );	mo_list=MFnewList( 1 );
	MFsetList( &mo_list, 0, MFident(" ") );	MFsig(mo_list);
	MFsetList( &mo_listlist, 1, mo_list );	MFsig(mo_listlist);  
      }

      mo=MFlist2array(mo_listlist, h,l);

      DEBUG("MATRIX finished: ");
      DEBUG(mo);
      return mo;
    }

  case TABLEAUX:
    {
      DEBUG("TABLEAUX... ");
      OP so1=s_t_s(so);
      DEBUG(so1);
      DEBUG(" TYPE: %d", s_o_k(so1));

      INT h,l,i,j,sizel,infsizel;
      MTcell content, inner, row, mo_elem;

      // If I (NT) understand well, so1 is an array of h rows of length l
      // For example, the skew tableau:
      //  56
      //   14
      //    23
      // is encoded as an array of 3 rows of length4:
      //  **23
      //  *14*
      //  56**
      // the '*' being null pointers, or something similar.
      // We transform this into the MuPAD object:
      //  [[2,1],[[5,6],[1,4],[2,3]]]
      h=s_m_hi(so1);
      l=s_m_li(so1);

      // determine the length of the inner partition
      int inner_length;
      if (l>0) {
	for (i=0; i<h; i++)
	  if (S_O_K(S_M_IJ(so1, i, 0)) != EMPTY) break;
	inner_length=i;
      } else {
	inner_length=0;
	h=0; // get rid of the special case of h empty rows
      }
      content = MFnewList( h );
      inner   = MFnewList( inner_length );

      for (i=0;i<h; i++) {
	// search for the first and last non null entry
	for (infsizel=0; infsizel<l; infsizel++)
	  if (S_O_K(S_M_IJ(so1, i, infsizel)) != EMPTY) break;
	for (sizel=infsizel; sizel<l; sizel++)
	  if (S_O_K(S_M_IJ(so1, i, sizel)) == EMPTY) break;
	row = MFnewList( sizel-infsizel );
	for (j=infsizel;j<sizel; j++) {
	  mo_elem=SYM_s2m_internal(S_M_IJ(so1, i, j));
	  if(!mo_elem) { /*MFfree(mo_list); MFfree(mo_listlist)*/return NULL; }
	  MFsetList( &row, j-infsizel, mo_elem );
	}
	MFsig(row);  // List finished
	MFsetList( &content, h-1-i, row );
	if (i<inner_length) {
	  MFsetList( &inner, i, MFint(infsizel) );
	}
      }
      MFsig(inner);
      MFsig(content);  // List finished
      MTcell skew_tableau = MFnewList(2);
      MFsetList(&skew_tableau, 0, inner);
      MFsetList(&skew_tableau, 1, content);
      MFsig(skew_tableau);
      DEBUG("TABLEAUX finished: ");
      DEBUG(skew_tableau);
      return skew_tableau;
    }


  case SCHUR: 
  case POW_SYM: 
  case HOM_SYM:
  case MONOMIAL:
  case ELM_SYM:
  case SCHUBERT:
  case MONOPOLY:
  case POLYNOM:
    {
      DEBUG("POLYNOM... ");

      INT len,i;
      {
	OP len_ob=callocobject();
	length(so, len_ob); len=s_i_i(len_ob); 
	SYMfreeall(len_ob);
      }

      // Set type of the following partitions to "s"
      if (knd==SCHUBERT) SYM_s2m_VECTOR_index=SYM_s2m_VECTOR_index_X;

      if (knd==SCHUR)    SYM_s2m_VECTOR_index=SYM_s2m_VECTOR_index_s;
      if (knd==POW_SYM)  SYM_s2m_VECTOR_index=SYM_s2m_VECTOR_index_p;
      if (knd==HOM_SYM)  SYM_s2m_VECTOR_index=SYM_s2m_VECTOR_index_h;
      if (knd==MONOMIAL) SYM_s2m_VECTOR_index=SYM_s2m_VECTOR_index_m;
      if (knd==ELM_SYM)  SYM_s2m_VECTOR_index=SYM_s2m_VECTOR_index_e;

      if (knd==MONOPOLY) SYM_s2m_MONOM_base=SYM_s2m_MONOM_base_q;

      if (len==0) {
	 mo=MFcopy(MVzero); 
      } else if (len==1) {
	 mo=SYM_s2m_internal( s_l_s(so)); 
	 if(!mo) return NULL;
      } else {
	mo=MFnewExpr(MFident("_plus"),len);
	
	for (i=1; i<=len; i++,so=s_l_n(so)) {
	  MTcell mo1;
	  mo1=SYM_s2m_internal( s_l_s(so));
	  if (!mo1) { /* MFfree(mo) */ return NULL; }
	  MFsetExpr(&mo, i, mo1);
	} 
	MFsig(mo);       // expr finished
      }
      
      
      DEBUG("POLYNOM finished: ");
      DEBUG(mo);
      return mo;
    }


  case MONOM:
    { 
      DEBUG("MONOM... ");

      MTcell mo_coeff, mo_base, mo_exp;

      mo_exp=SYM_s2m_internal( s_mo_s(so));
      if (!mo_exp) return NULL;

      switch (SYM_s2m_MONOM_base){
      case SYM_s2m_MONOM_base_nothing:
	mo_base=mo_exp;
	break;
      case SYM_s2m_MONOM_base_q:
	{
	  if (MFisList(mo_exp) && MFnopsList(mo_exp)==1)
	    mo_exp=MFgetList(&mo_exp,0);
	  if (MFequal(mo_exp, MVzero) )
	    mo_base=MFcopy(MVone);
	  else
	    mo_base=mupad_calc("_power", MFident("q"), mo_exp);
	  break;
	}
      default:
	MFerror("(SYM) Internal error: unknown MONOM base");
      };


      // This should go in functions SYM_s2m_push() and SYM_s2m_pop() ?!
      char const* save_VECTOR_index=SYM_s2m_VECTOR_index;
      int         save_VECTOR_reverse=SYM_s2m_VECTOR_reverse;
      int         save_MONOM_base=SYM_s2m_MONOM_base;
      SYM_s2m_VECTOR_index=SYM_s2m_VECTOR_index_nothing;
      SYM_s2m_VECTOR_reverse=0;
      SYM_s2m_MONOM_base=SYM_s2m_MONOM_base_q;
      
      mo_coeff=SYM_s2m_internal( s_mo_k(so));
      if (!mo_coeff) { /*MFfree(mo_base);*/ return NULL; }
      
      SYM_s2m_VECTOR_index=save_VECTOR_index;
      SYM_s2m_VECTOR_reverse=save_VECTOR_reverse;
      SYM_s2m_MONOM_base=save_MONOM_base;
      
      switch(MFdom(mo_coeff)) {
      case DOM_INT:
	switch (MFlong(mo_coeff)) {
	case 1: 
	  mo=mo_base;
	  MFfree(mo_coeff);
	  break;
// 	case -1:
// 	  mo=mo_base;
// 	  //	  MUP_set_spec(mo,1);  // set the  MINUS bit
// 	  MFspec(mo)|=MINUS_BIT;
// 	  MFfree(mo_coeff);
// 	  break;
	default:
	  mo=mupad_calc("_mult", mo_base, mo_coeff);
	}
	break;
      default: 
	mo=mupad_calc("_mult", mo_base, mo_coeff);
      }

      DEBUG("MONOM finished: ");
      DEBUG(mo);
      return mo;
    }

  case SYMLIST:
    { // ????
      DEBUG("SYMLIST... ");

      INT len,i;
      {
	OP len_ob=callocobject();
	length(so, len_ob); len=s_i_i(len_ob); 
	SYMfreeall(len_ob);
      }

      mo=MFnewList(len);
      for (i=0; i<len; i++,so=s_l_n(so)) {
	MTcell mo1=SYM_s2m_internal( s_l_s(so));
	if (!mo1) { /*MFfree(mo);*/ return NULL; }
	MFsetList(&mo, i, mo1);
      } 
      MFsig(mo);  // List finished
      
      DEBUG("SYMLIST finished: ");
      DEBUG(mo);
      return mo;
    }
  case VECTOR: 
    {
      DEBUG("VECTOR... ");

      INT len, start, i;
      len=S_V_LI(so);
      if (SYM_s2m_VECTOR_index==SYM_s2m_VECTOR_index_nothing) {
	start=0;
	mo=MFnewList( len );
      } else {
	start=2;
	mo=MFnewExpr( MFident("_index"), len+1 );
	MFsetExpr( &mo, 1, MFident(*((char**)&SYM_s2m_VECTOR_index)) );
      }

      for (i=0;i<len; i++) {
	OP so1=S_V_I(so, (SYM_s2m_VECTOR_reverse?len-1-i:i) );
	MTcell mo1=SYM_s2m_internal(so1);
	if (!mo1) { /*MFfree(mo);*/ return NULL; }
	MFopSet( mo, i+start, mo1 );
      }
      MFsig(mo);  // Expr finished

      
      DEBUG("VECTOR finished: ");
      DEBUG(mo);
      return mo;
    }
  default:
    {
      DEBUG("ERROR: UNKNOWN TYPE: %ld\n", knd);
      return NULL;
    }
  }

  return mo;
}
