    /**************************************************************************\

    MODULE: vec_GF2

    SUMMARY:

    The class Vec<GF2> is explicitly specialized.
    It behaves much like a generic Vec<T> (see vector.txt),
    but there are some differences.

    For efficiency, elements of a Vec<GF2> are "packed" into a word.
    You can still use subscript notation v[i] or v(i).
    For const vectors, these evaluate to values of type const GF2.
    For non-const vectors, these evaluate to values of the
    special type ref_GF2, which is defined in the GF2 header file.

    There are implicit conversions from ref_GF2 to const GF2
    and from GF2& to ref_GF2.  Therefore, if you want to declare
    a function that takes a non-const reference to a GF2, you
    should declare the parameter of type ref_GF2: this will
    allow you to pass variables of type GF2 as well as
    elements of vec_GF2's obtained through indexing.

    As an alternative, one can use the get and put methods below to access
    vector elements.

    There is one subtle but important difference in the semantics
    of Vec<GF2> and that of generic NTL vectors.  With a Vec<GF2>, whenever its
    length is increased (via SetLength), the "new" bits are always 0.
    For example, if v.length() == 20, then

       v.SetLength(10); v.setLength(20);

    will effectively clear bits 10..19 of v.
    This is quite different from the semantics of generic NTL vectors, where
    the above sequence would not change the value of v at all.
    One has to be aware of this difference, but it will not matter
    in most ordinary circumstances.

    \**************************************************************************/

    template<>
    class Vec<GF2> {

    public:

       Vec(); // 0 length vector
       Vec(INIT_SIZE_TYPE, long n); // initialize to length n
                                    // usage: Vec(INIT_SIZE, n)

       Vec(const Vec<GF2>& a); // copy constructor
       Vec& operator=(const Vec<GF2>& a); // assignment
       ~Vec(); // destructor

       void SetLength(long n); // set length to n bits
       void SetLength(long n, GF2 a);
          // set length to n, if length increases, initialize new bits to a

       void SetMaxLength(long n); // allocate space for n bits

       long length() const; // current length, in bits

       long MaxLength() const; // maximum length, i.e., the maximum
                               // value passed to either SetLength or SetMaxLength
                               // since creation or last kill

       long allocated() const; // number of bits for which space is allocated;
                               // if n <= v.allocated(), then v.SetLength(n)
                               // will not result in any memory re-allocation.

       // INVARIANT:
       //    length() <= MaxLength() <= allocated() < 2^(NTL_BITS_PER_LONG-4)

       void FixLength(long n); // fix length to n bits
       // can only be applied after default initialization or kill

       void FixAtCurrentLength();
       // fixes the length at the cuurent length and prohibits
       // all future length changes.

       // It is required that length() == MaxLength() when called.

       // EXCEPTIONS: if length() != MaxLength() and error is raised;
       // Strong ES.

       long fixed() const; // test if length has been fixed

       void kill(); // free space and make length 0

       const GF2 get(long i) const; // fetch value at index i (indexing from 0)

       void put(long i, GF2 a); // write value a to index i (indexing from 0)
       void put(long i, long a);

    // Here are the subscripting operators, defined using the
    // "helper" class ref_GF2

       ref_GF2 operator[](long i);
       ref_GF2 operator()(long i);

       const GF2 operator[](long i) const;
       const GF2 operator()(long i) const;

       void swap(Vec<GF2>& y);
       // swap with y (fast: just swaps pointers)

       void append(GF2 a);
       // append a to end of vector

       void append(const Vec<GF2>& w);
       // append w to end of vector

    // Some partial STL compatibility...also used
    // to interface with the Matrix template class

       typedef GF2 value_type;
       typedef ref_GF2 reference;
       typedef const GF2 const_reference;

    };

    void swap(Vec<GF2>& x, Vec<GF2>& y);
    // swap x and y (fast pointer swap)

    void append(Vec<GF2>& v, GF2 a);
    // append a to v

    void append(Vec<GF2>& v, const Vec<GF2>& a);
    // append a to v

    // equality operators:

    long operator==(const Vec<GF2>& a, const Vec<GF2>& b);
    long operator!=(const Vec<GF2>& a, const Vec<GF2>& b);

    // I/O operators:

    ostream& operator<<(ostream& s, const Vec<GF2>& a);
    istream& operator>>(istream& s, Vec<GF2>& a);

    // The I/O format is [a_0 a_1 ... a_{n-1}], where each a_i is "0" or "1".
    // On input, the a_i may be arbitrary integers, which are reduced mod 2.

    typedef Vec<GF2> vec_GF2;  // backward compatibility

    // utility routines:

    void clear(vec_GF2& x); // clear all bits--length unchanged
    long IsZero(const vec_GF2& a); // test if all bits are zero

    void shift(vec_GF2& x, const vec_GF2& a, long n);
    vec_GF2 shift(const vec_GF2& a, long n);
    // x = a shifted n places, where n may be positive or negative.
    // Generally, x[i] = a[i-n], so positive n shifts to a higher index.
    // The length of x is set to the length of a, and bits
    // are zero-filled or discarded as necessary.

    void reverse(vec_GF2& x, const vec_GF2& a); // c = a reversed
    vec_GF2 reverse(const vec_GF2& a);

    long weight(const vec_GF2& a); // return number of 1 bits in a

    void random(vec_GF2& x, long n);  // x = random vector of length n
    vec_GF2 random_vec_GF2(long n);

    // arithmetic operations over GF(2):

    void add(vec_GF2& x, const vec_GF2& a, const vec_GF2& b);
    void sub(vec_GF2& x, const vec_GF2& a, const vec_GF2& b);
    void negate(vec_GF2& x, const vec_GF2& a);

    void mul(vec_GF2& x, const vec_GF2& a, GF2 b);
    void mul(vec_GF2& x, const vec_GF2& a, long b);

    void mul(vec_GF2& x, GF2 a, const vec_GF2& b);
    void mul(vec_GF2& x, long a, const vec_GF2& b);
    // x = a * b

    void InnerProduct(ref_GF2 x, const vec_GF2& a, const vec_GF2& b);
    // vectors may differ in length

    void VectorCopy(vec_GF2& x, const vec_GF2& a, long n);
    vec_GF2 VectorCopy(const vec_GF2& a, long n);
    // x = a copy of a of length exactly n.
    // The input is truncated or padded with zeroes, as necessary.

    // arithmetic operator notation:

    vec_GF2 operator+(const vec_GF2& a, const vec_GF2& b);
    vec_GF2 operator-(const vec_GF2& a, const vec_GF2& b);
    vec_GF2 operator-(const vec_GF2& a);

    // scalar mul:

    vec_GF2 operator*(const vec_GF2& a, GF2 b);
    vec_GF2 operator*(const vec_GF2& a, long b);

    vec_GF2 operator*(GF2 a, const vec_GF2& b);
    vec_GF2 operator*(long a, const vec_GF2& b);

    // inner product:

    inline GF2 operator*(const vec_GF2& a, const vec_GF2& b);

    // assignment operator notation:

    vec_GF2& operator+=(vec_GF2& x, const vec_GF2& a);
    vec_GF2& operator-=(vec_GF2& x, const vec_GF2& a);

    vec_GF2& operator*=(vec_GF2& x, GF2 a);
    vec_GF2& operator*=(vec_GF2& x, long a);