/* ============================= C MeatAxe ==================================
   File:        $Id: issub.c,v 1.1.1.1 2007/09/02 11:06:17 mringe Exp $
   Comment:     Compare vector spaces
   --------------------------------------------------------------------------
   (C) Copyright 1998 Michael Ringe, Lehrstuhl D fuer Mathematik,
   RWTH Aachen, Germany  <mringe@math.rwth-aachen.de>
   This program is free software; see the file COPYING for details.
   ========================================================================== */


#include "meataxe.h"

MTX_DEFINE_FILE_INFO


/**
!section algo.etc
 ** Vector space incidence relation.
 ** @param sub
    Generating set for the first space, $U$.
 ** @param space
    Pointer to a basis for the second space, $V$.
 ** @param ngen
    Number of vectors in |sub| to consider.
 ** @return
    $1$ if $U\leq V$, $0$ if $U\not\leq V$, and $-1$ on error.
!description
    This function compares two vector spaces $U,V\in\GF{q}^n$ and returns $1$,
    if $U\leq V$.
    The spaces to compare are given as matrices where the rows of |sub| 
    (linearly) generate $U$ and the rows of |space| generate $V$.
    Thus, |sub| and |space| must be matrices over the same field and with the same
    number of columns. Also, |space| must be in full echelon form while 
    there is no further restriction on |sub|.

    In normal mode, |ngen| is 0. Then, the rows of |sub| are checked one-by-one
    to see if they are in the span of the rows of |space|. If this test passes
    for each row of |sub|, the return value is 1, otherwise it is 0. 
    There is no special return value for the cases $U=V$ or $U>V$.

    If |ngen| is different from zero, the function assumes that $U$ is 
    generated by the first |ngen| rows, and only this number of rows are
    checked. For example, $U$ may be a cyclic submodule, 
    which is generated from a single vector under the action of an algebra. 
    Then, one only needs to check if the generating vector, which 
    is supposed to be the first row of |sub|, is contained in $V$.
 ** @see 
 **/

int IsSubspace(const Matrix_t *sub, const Matrix_t *space, int ngen)

{
    long nvec, spcdim, i;
    PTR tmp, y;

    /* Check the arguments
       ------------------- */
    if (!MatIsValid(sub) || !MatIsValid(space))
    {
	MTX_ERROR1("%E",MTX_ERR_BADARG);
	return -1;
    }
    if (sub->Field != space->Field || sub->Noc != space->Noc)
    {
	MTX_ERROR1("%E",MTX_ERR_INCOMPAT);
	return -1;
    }
    if (space->PivotTable == NULL)
    {
	MTX_ERROR1("space: %E",MTX_ERR_NOTECH);
	return -1;
    }

    /* Decide how many vectors from <sub> we shall check
       ------------------------------------------------- */
    FfSetField(space->Field);
    FfSetNoc(space->Noc);
    spcdim = space->Nor;
    nvec = sub->Nor;
    if (ngen > 0 && ngen < nvec)
	nvec = ngen;

    /* Allocate workspace 
       ------------------ */
    tmp = FfAlloc(1);
    if (tmp == NULL)
    {	
	MTX_ERROR("Cannot allocate workspace");
	return -1;
    }

    /* Check if vectors from <sub> are in the span of <space>
       ------------------------------------------------------ */
    for (i = nvec, y = sub->Data; i > 0; --i, FfStepPtr(&y))
    {
	FEL f;
	FfCopyRow(tmp,y);
	FfCleanRow(tmp,space->Data,spcdim,space->PivotTable);
        if (FfFindPivot(tmp,&f) >= 0) 
	    break;
    }

    /* Clean up and return the result
       ------------------------------ */
    SysFree(tmp);
    return (i <= 0);
}


