/* *
   File:        amlv.c
   Author:      Paul Komarek
   Created:     Mon May 20 14:49:01 EDT 2002
   Description: Definitions for Long Integer Dynamic vectors

   Copyright (C) 2002, AUTON lab or Andrew Moore
*/

#include <stdio.h>

#include "ambs.h"      /* Very basic operations */
#include "amma.h"      /* Fast, non-fragmenting, memory management */
#include "amar.h"      /* Array stuff */
#include "amiv.h"      /* String array definition */
#include "amlv.h"

/* An lvec is an array of long integers, with interface functions that are
   very similar to those of ivecs.  See amiv.h for more information about
   these functions.  Note that the indices and lengths in lvecs are regular
   integers.
*/

/* Private function prototypes */
void assert_lvec_shape(lvec *lv,int size,char *name);

#define LVEC_CODE 51240

int Lvecs_mallocked = 0;
int Lvecs_freed = 0;

#ifdef AMFAST

#define NOTHING_TO_DO
#define check_lvec_code(lv, name) NOTHING_TO_DO
#define check_lvec_access(iv, i ,name) NOTHING_TO_DO

#else

void check_lvec_code(const lvec *lv, char *name); /* Private */
void check_lvec_code(const lvec *lv, char *name)
{
  if ( lv == NULL )
  {
    fprintf(stderr,"NULL lvec passed in operation %s\n", name);
    my_error("lvec data structure");
  }
  if ( lv->lvec_code != LVEC_CODE )
  {
    fprintf(stderr,"Attempt to access a non-allocated Long Integer Vector\n");
    fprintf(stderr,"This is in the operation %s\n", name);
    my_error("lvec data structure error");
  }
  if ( lv->array_size < lv->size )
    my_error("check_lvec_code: array_size and size muddled");
}

void check_lvec_access(const lvec *lv, int i, char *name); /* Private */
void check_lvec_access(const lvec *lv, int i, char *name)
{
  check_lvec_code(lv, name);

  if ( i < 0 || i >= lv->size )
  {
    fprintf(stderr,"In operation \"%s\"\n", name);
    fprintf(stderr, "the lvec (long int dynamic vector) has size=%d\n",
	    lv->size);
    fprintf(stderr,"You tried to use index i=%d\n",i);
    fprintf(stderr,"Here is the lvec that was involved:\n");
    fprintf_lvec(stderr,"lvv", lv, "\n");
    my_error("check_lvec_access");
  }
  if ( lv->array_size < lv->size )
    my_error("check_lvec_code: array_size and size muddled");
}

#endif

void assert_lvec_shape(lvec *lv,int size,char *name)
{
  check_lvec_code(lv,name);

  if ( size != lv->size )
  {
    fprintf(stderr,"In operation \"%s\"\n", name);
    fprintf(stderr,"the lvec (long int dynamic vector) has size=%d\n",
	    lv->size);
    fprintf(stderr,"But should have been predefined with the shape:\n");
    fprintf(stderr,"size = %d\n", size);
    my_error("assert_lvec_shape");
  }
}


/***************************************************************************/
/* simple lvec allocation functions (creation and destruction)             */
/***************************************************************************/

lvec *mk_lvec(int size)
{
  lvec *result = AM_MALLOC(lvec);
  if ( size < 0 ) my_error("mk_lvec : size < 0 illegal");
  result -> lvec_code = LVEC_CODE;
  result -> array_size = size;
  result -> size = size;
  result -> larr = am_malloc_longs(size);
  Lvecs_mallocked += 1;
  return(result);
}

void free_lvec(lvec *lv)
{
  check_lvec_code(lv,"free_lvec");
  lv->lvec_code = 7777;

  am_free_longs(lv->larr, lv->array_size);
  am_free((char *)lv, sizeof(lvec));

  Lvecs_freed += 1;
}

lvec *mk_sequence_lvec(long start_value, long end_value)
{
  int size, i;
  lvec *lv;

  size = end_value - start_value;
  lv = mk_lvec(size);

  for ( i = 0 ; i < size ; i++ ) lvec_set(lv, i, start_value+i);
  return lv;
}

lvec *mk_identity_lvec(int size)
{
  return mk_sequence_lvec(0, size);
}

lvec *mk_constant_lvec(int size, long value)
{
  lvec *lv;
  lv = mk_lvec(size);
  constant_lvec(lv, value);
  return(lv);
}

lvec *mk_zero_lvec(int size)
{
  return (mk_constant_lvec(size, 0));
}

lvec *mk_lvec_1(long x0)
{
  lvec *result;
  result = mk_lvec(1);
  lvec_set(result, 0, x0);
  return result;
}

lvec *mk_lvec_2(long x0, long x1)
{
  lvec *result;
  result = mk_lvec(2);
  lvec_set(result, 0, x0);
  lvec_set(result, 1, x1);
  return result;
}

lvec *mk_lvec_3(long x0, long x1, long x2)
{
  lvec *result;
  result = mk_lvec(3);
  lvec_set(result, 0, x0);
  lvec_set(result, 1, x1);
  lvec_set(result, 2, x2);
  return result;
}

lvec *mk_lvec_4(long x0, long x1, long x2, long x3)
{
  lvec *result;
  result = mk_lvec(4);
  lvec_set(result, 0, x0);
  lvec_set(result, 1, x1);
  lvec_set(result, 2, x2);
  lvec_set(result, 3, x3);
  return result;
}

lvec *mk_lvec_5(long x0, long x1, long x2, long x3, long x4)
{
  lvec *result;
  result = mk_lvec(5);
  lvec_set(result, 0, x0);
  lvec_set(result, 1, x1);
  lvec_set(result, 2, x2);
  lvec_set(result, 3, x3);
  lvec_set(result, 4, x4);
  return result;
}

lvec *mk_lvec_6(long x0, long x1, long x2, long x3, long x4, long x5)
{
  lvec *result;
  result = mk_lvec(6);
  lvec_set(result, 0, x0);
  lvec_set(result, 1, x1);
  lvec_set(result, 2, x2);
  lvec_set(result, 3, x3);
  lvec_set(result, 4, x4);
  lvec_set(result, 5, x5);
  return result;
}

void lvec_malloc_report(void)
{
  if ( Lvecs_mallocked > 0 ) {
    fprintf(stdout,
	    "# Integer Vectors  (datatype lvec) currently allocated: %d\n",
	    Lvecs_mallocked - Lvecs_freed);

    if ( Lvecs_mallocked - Lvecs_freed != 0 ) {
      fprintf(stdout,
	      "#       Number of lvec allocations since program start:  %d\n",
             Lvecs_mallocked);
      fprintf(stdout,
	      "#       Number of lvec frees since program start:  %d\n#\n",
	      Lvecs_freed);
    }
  }
}

lvec *mk_slvec_1(long v1)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_slvec_2(long v1, long v2)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_slvec_3(long v1, long v2, long v3)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_slvec_4(long v1, long v2, long v3, long v4)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_slvec_5(long v1, long v2, long v3, long v4, long v5)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec_array *mk_array_of_empty_lvecs(int size)
{
  int i;
  lvec *empty_lv;
  lvec_array *lva;

  lva = mk_empty_lvec_array();
  empty_lv = mk_lvec(0);

  for ( i = 0 ; i < size ; i++ ) add_to_lvec_array(lva, empty_lv);

  free_lvec(empty_lv);
  return(lva);
}

#define INITIAL_lvec_ARRAY_SIZE 10

lvec_array *mk_empty_lvec_array (void)
{
  lvec_array *lvecarr;
  lvecarr = AM_MALLOC(lvec_array);
  lvecarr->size = 0;
  lvecarr->array_size = INITIAL_lvec_ARRAY_SIZE;
  lvecarr->array = AM_MALLOC_ARRAY(lvec_ptr, lvecarr->array_size);
  return lvecarr;
}

lvec_array *mk_copy_lvec_array (lvec_array *lvecarr)
{
  lvec_array *new_ar;
  int i;

  new_ar = mk_empty_lvec_array();
  for ( i = 0 ; i < lvec_array_size(lvecarr) ; i++ ) {
    add_to_lvec_array(new_ar, lvec_array_ref(lvecarr,i));
  }

  return(new_ar);
}

void free_lvec_array (lvec_array *lvecarr)
{
  int i;
  for ( i = 0 ; i < lvec_array_size(lvecarr) ; i++ ) {
    if ( lvecarr->array[i] != NULL ) free_lvec(lvecarr->array[i]);
  }
  AM_FREE_ARRAY(lvecarr->array, lvec_ptr, lvecarr->array_size);
  AM_FREE(lvecarr, lvec_array);
}



/***************************************************************************/
/* fancy lvec allocation functions that might belong in other catagories   */
/***************************************************************************/

/* Return x with y appended on the end */
lvec *mk_lvec_append(lvec *x,lvec *y)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_lvec_from_file(FILE *fp, char **r_errmess)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

/* A slvec is sorted and has no duplicates */
lvec *mk_add_to_slvec(lvec *slv,long value)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_identity_slvec(int size)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec_array *mk_transpose_lvec_array( lvec_array *lva )
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec_array *mk_lvec_array_subset(lvec_array *lva, ivec *rows)
{
  int size, i, row;
  lvec *lv;
  lvec_array *result;

  size   = ivec_size(rows);
  result = mk_empty_lvec_array();
  for ( i = 0 ; i < size ; i++ ) {
    row = ivec_ref(rows,i);
    lv = lvec_array_ref(lva, row);
    add_to_lvec_array(result, lv);
  }
  return result;
}

lvec *mk_reverse_lvec(lvec *x)
{
  int i;
  lvec *a;
  a = mk_lvec(lvec_size(x));
  for (i=0; i<lvec_size(x); i++) lvec_set(a, lvec_size(x)-i-1, lvec_ref(x,i));
  return a;
}

lvec *mk_indices_of_sorted_lvec(lvec *v)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}


/***************************************************************************/
/* lvec copy/derive/change-type functions                                  */
/***************************************************************************/

void copy_lvec_subset(const lvec *lv, int start, int size, lvec *r_lv)
{
  int i;
  for (i=start; i < start+size; i++) lvec_set(r_lv, i-start, lvec_ref(lv, i));
}

void copy_lvec(const lvec *lv, lvec *r_lv)
{
  copy_lvec_subset(lv, 0, lvec_size(lv), r_lv);
}

lvec *mk_lvec_from_larr(long *larr, int size)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

long *mk_larr_from_lvec(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_copy_lvec_subset(lvec *lv, int start, int size)
{
  lvec *result;
  result = mk_lvec(size);
  copy_lvec_subset(lv, start, size, result);
  return result;
}

lvec *mk_copy_lvec(const lvec *lv)
{
  lvec *result;
  result = mk_lvec(lvec_size(lv));
  copy_lvec(lv, result);
  return result;
}

string_array *mk_string_array_from_lvec(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

char *mk_string_from_lvec(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_lvec_from_lvec_array(lvec_array *lva)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_slvec_from_lvec(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_lvec_from_string(char *s)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

/* Turns a space separated string into a slvec.
   Example: "3 1 4 1 5 9" ====> { 1 , 3 , 4 , 5 , 9 } */
lvec *mk_slvec_from_string(char *s)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

/* Returns lvec of size lvec_size(rows) in which
    result[i] = x[rows[i]] */
lvec *mk_lvec_subset(lvec *x, ivec *rows)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}



/***************************************************************************/
/* lvec set element functions                                              */
/***************************************************************************/

long safe_lvec_ref(const lvec *lv, int i)
{
  check_lvec_access(lv, i,"lvec_ref");
  return (lv->larr[i]);
}

void safe_lvec_increment(lvec *lv, int i, long value)
{
  check_lvec_access(lv, i, "lvec_increment");
  lv->larr[i] += value;
}

void copy_larr_to_lvec(long *larr, int size, lvec *r_lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}

void constant_lvec(lvec *lv, long value)
{
  int i;
  for ( i = 0 ; i < lvec_size(lv) ; i++ ) lvec_set(lv, i, value);
}

void zero_lvec(lvec *lv)
{
  constant_lvec( lv, 0);
}

#define lvec_array_ref_set(lva,i,j,x) lvec_set(lvec_array_ref(lva,i),j,x)

void lvec_array_set (lvec_array *lva, int idx, lvec *lv)
{
  if ((idx < 0) || (lva == NULL) || (idx >= lva->size)) {
    my_error("lvec_array_set: called with incompatible arguments");
  }
  if (lva->array[idx] != NULL) free_lvec(lva->array[idx]);
  lva->array[idx] = (lv == NULL) ? NULL : mk_copy_lvec(lv);
}


/***************************************************************************/
/* lvec get element functions                                              */
/***************************************************************************/

void safe_lvec_set(lvec *lv, int i, long value)
{
  check_lvec_access(lv, i, "lvec_set");
  lv->larr[i] = value;
}

void copy_lvec_to_larr(lvec *lv, long *larr)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}

#define lvec_array_ref_ref(lva,i,j) lvec_ref(lvec_array_ref(lva,i),j)

lvec *safe_lvec_array_ref (lvec_array *lvecarr, int idx)
{
  lvec *result;
  if ( idx < 0 || idx >= lvec_array_size(lvecarr) ) {
    char msg[500];
    sprintf( msg, "lvec_array_ref: index=%d is out of bounds [0,%d].",
	     idx, lvec_array_size(lvecarr)-1 );
    result = NULL;
    my_error(msg);
  }
  else result = lvecarr->array[idx];
  return result;
}


/***************************************************************************/
/* lvec element summary functions                                          */
/***************************************************************************/

int lvec_num_of_given_value(lvec *lv, long value)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

int lvec_num_zero_entries(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

int lvec_num_nonzero_entries(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

int lvec_min(const lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

int lvec_max(const lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

int lvec_argmin(const lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

int lvec_argmax(const lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

int  find_index_in_lvec(const lvec *lv, long value) /* not found => -1 */
{
  int result;
  int i;

  result = -1;
  for (i=0; result < 0 && i < lvec_size(lv); i++) {
    if (value == lvec_ref(lv, i)) result = i;
  }
  return(result);
}

ivec *find_all_in_lvec(const lvec *lv, long value)
{
  ivec *result;
  int i;

  result = mk_ivec(0);
  for (i=0; i < lvec_size(lv); i++) {
    if (value == lvec_ref(lv, i)) add_to_ivec( result, i);
  }
  return result;
}

/* Starts at index=hint, works outward.  -1 => not found */
int  find_index_in_lvec_hint(const lvec *lv, long value, int hint)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

int  find_index_in_sorted_lvec(lvec *slv, long val) /* -1 => failure*/
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

bool is_in_lvec (lvec *lv, long value)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

int  safe_lvec_size(const lvec *lv)
{
  check_lvec_code(lv, "lvec_size");
  return(lv->size);
}

int  lvec_array_size (lvec_array *lvecarr)
{
  return(lvecarr->size);
}

int  index_of_longest_lvec(lvec_array *lva)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

#ifdef AMFAST
#define debugger_assert_is_slvec(slv)
#else

int Num_big_slvec_checks = 0;

void debugger_assert_is_slvec(const lvec *slv); /* Private */
void debugger_assert_is_slvec(const lvec *slv)
{
  bool big;

  big = (lvec_size(slv) > 10);

  if ( !big || (Num_big_slvec_checks < 100) ) {
    if ( !is_slvec(slv) ) {
      fprintf_lvec(stdout,"slv", slv, "\n");
      my_error("The above lvec was not a slvec (SetLVEC) because it was not\n"
	       "sorted. It was passed to a slvec operation in amlv.c\n");
    }
    if ( big ) Num_big_slvec_checks += 1;
  }
}
#endif

bool is_slvec(const lvec *lv)
{
  bool result;
  int size, i;

  result = TRUE;
  size = lvec_size(lv);
  for ( i = 0 ; result && i < size-1 ; i++ ) {
    if ( lvec_ref(lv, i) >= lvec_ref(lv,i+1) ) result = FALSE;
  }
  return result;
}

int  slvec_size(const lvec *slv)
{
  return lvec_size(slv);
}

long slvec_min(const lvec *slv)
{
#ifndef AMFAST
  if ( lvec_size(slv) <= 0 ) my_error("slvec_min : empty set");
#endif
  return lvec_ref(slv, 0);
}

long slvec_max(const lvec *slv)
{
#ifndef AMFAST
  if ( lvec_size(slv) <= 0 ) my_error("slvec_max : empty set");
#endif
  return lvec_ref(slv, lvec_size(slv)-1);
}

int find_index_in_slvec(const lvec *slv, long val) /* -1 => failure*/
{
  int size, result, lo, mid, hi, loval, midval, hival;

  size = lvec_size(slv);
  debugger_assert_is_slvec(slv);

  if ( size == 0 ) result = 0;
  else {
    loval = lvec_ref(slv, 0);
    if ( val <= loval ) result = 0;
    else {
      lo = 0;
      hi = size-1;
      hival = lvec_ref( slv, hi);
      if ( val > hival ) result = size;
      else {
        while (hi > lo+1) {
          mid = (lo + hi) / 2;
          midval = lvec_ref(slv, mid);
          if ( midval < val ) {
            lo = mid;
            loval = midval;
          }
          else {
            hi = mid;
            hival = midval;
          }
        }
        if (loval == val) result = lo;
        else result = hi;
      }
    }
  }

#ifndef AMFAST
  {
    bool ok;
    if ( size == 0 ) ok = result == 0;
    else if ( val > slvec_max(slv) )  ok = result == size;
    else if ( val <= slvec_min(slv) ) ok = result == 0;
    else {
      ok = (val <= lvec_ref(slv, result));
      ok = ok && (lvec_ref(slv, result-1) < val);
    }

    if ( !ok ) my_error("find_index_in_slvec() : bug\n");
  }
#endif

  return result;
}

int index_in_slvec(const lvec *slv, long value) /* -1 => not found */
{
  int idx;
  idx = find_index_in_slvec(slv, value);
  if ((idx >= lvec_size(slv)) || (value != lvec_ref(slv, idx))) idx = -1;
  return idx;
}

bool is_in_slvec(const lvec *slv, long value)
{
  return index_in_slvec(slv, value) >= 0;
}

/***************************************************************************/
/* lvec shape operations (changes length)                                  */
/***************************************************************************/

void lvec_remove(lvec *lv, int idx)
{
  int i;
  int lsize = lvec_size(lv);

#ifndef AMFAST
  if ( lsize <= 0 ) my_error("lvec_remove: empty lvec");
  if ( idx < 0 || idx >= lsize ) my_error("lvec_remove: bad index");
#endif /* #ifndef AMFAST */

  for (i=idx; i < lsize-1; i++) lvec_set( lv, i, lvec_ref(lv, i+1));
  lv->size -= 1;
}

void lvec_remove_last_element(lvec *lv)
{
#ifndef AMFAST
  if (lvec_size(lv) <= 0) my_error("lvec_remove_last_elt: empty lvec");
#endif /* #ifndef AMFAST */

  lv->size -= 1;
}

void lvec_remove_last_n_elements( lvec *lv, int n)
{
  lv->size -= n;
  if (lv->size < 0) lv->size = 0;
}

void lvec_remove_value(lvec *lv, int val) /* Removes all occurances of val */
{
  int lvsize, numfound, idx, i, lvval;

  /* This implementation is linear time (each element is read at most once,
     and set at most once).  The ivec implementation is (at worst)
     quadratic. */

  lvsize   = lvec_size( lv);
  numfound = 0;
  i        = 0;
  while (1) {
    /* compute src index */
    idx = i + numfound;
    if (idx >> lvsize) break;

    /* get src val and check */
    lvval = lvec_ref( lv, idx);
    if (lvval == val) {
      /* elem == val: don't copy */
      numfound += 1;
      continue;
    }
    else {
      /* elem != val: copy */
      lvec_set( lv, i, lvval);
      i += 1;
    }
  }

  lv->size -= numfound;
  return;
}

void add_to_lvec(lvec *lv, int new_val)
{
  int size;

  check_lvec_code(lv, "add_to_lvec");

  if ( lv->array_size < 0 ) {
    my_error("An lvec should never have a negative array_size if\n"
	     "it was constructed using legal API calls");
  }

  if ( lv->size > lv->array_size ) {
    my_error("An lvec should never have size greater than array_size if\n"
	     "it was constructed using legal API calls");
  }

  size = lv->size;

  if (size == lv->array_size)
  {
    int new_array_size = 2 * size + 10;
    long *larr_new;
    int i;

    larr_new = AM_MALLOC_ARRAY(long, new_array_size);

    for (i=0; i < size; i++) larr_new[i] = lv->larr[i];
    AM_FREE_ARRAY(lv->larr, long, size);
    lv->larr = larr_new;
    lv->array_size = new_array_size;
  }
  lv->larr[size] = new_val;
  lv->size += 1;
}

void add_to_sorted_lvec(lvec *slv, int val)
{
  int slvsize, i;
  add_to_lvec( slv, 0);
  slvsize = lvec_size(slv);

  for (i=slvsize-2; i >= 0 && val < lvec_ref(slv, i); i--) {
    lvec_set(slv, i+1, lvec_ref(slv, i));
  }
  lvec_set(slv, i+1, val);
}

void lvec_insert(lvec *lv, int idx, long val) /* iv_after[index] = val */
{
  int i;
  add_to_lvec(lv, 0);
  for (i=lvec_size(lv)-1; i > idx; i--) lvec_set(lv, i, lvec_ref(lv, i-1));
  lvec_set(lv, idx, val);
}

void append_lvec_to_lvec(lvec *x, lvec *y)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}

#define add_to_lvec_array_ref(lva,i,x) add_to_lvec(lvec_array_ref(lva,i),x)

void add_to_lvec_array (lvec_array *lvecarr, lvec *this_lvec)
{
  if ( lvecarr -> size == lvecarr -> array_size ) {
    int new_size = 2 + 2 * lvecarr->array_size;
    lvec **new_array = AM_MALLOC_ARRAY(lvec_ptr, new_size);
    int i;
    for (i=0; i < lvecarr -> array_size; i++) new_array[i] = lvecarr->array[i];
    AM_FREE_ARRAY(lvecarr->array, lvec_ptr, lvecarr->array_size);
    lvecarr -> array = new_array;
    lvecarr -> array_size = new_size;
  }

  if (this_lvec == NULL) lvecarr->array[lvecarr->size] = NULL;
  else lvecarr->array[lvecarr->size] = mk_copy_lvec( this_lvec);
  lvecarr->size += 1;
}

void lvec_array_remove(lvec_array *lva,int idx)
{
  int i;
  lvec *lv;
  lv = lvec_array_ref(lva, idx);
  if ( lv != NULL ) free_lvec(lv);
  for ( i = idx ; i < lva->size-1 ; i++ ) lva->array[i] = lva->array[i+1];
  lva->array[lva->size-1] = NULL;
  lva->size -= 1;
}

void lvec_array_remove_last_element( lvec_array *lva)
{
  int size;
  lvec *lv;

#ifndef AMFAST
  if (lvec_array_size(lva) <= 0) {
    my_error("lvec_array_remove_last_elementt: empty lvec_array");
  }
#endif /* #ifndef AMFAST */

  size = lvec_array_size( lva);
  lv   = lvec_array_ref(lva, size-1);
  if (lv != NULL) free_lvec(lv);
  lva->size -= 1;

  return;
}

void lvec_array_remove_last_n_elements( lvec_array *lva, int n)
{
  int size, newsize, i;
  lvec *lv;

  /* Adjust size. */
  size    = lvec_array_size(lva);
  newsize = size - n;
  if (newsize < 0) newsize = 0;

  /* Free lvecs. */
  for (i=size-1; i>=newsize; --i) {
    lv = lvec_array_ref(lva, i);
    if (lv != NULL) free_lvec(lv);
  }

  lva->size = newsize;

  return;
}

void add_to_slvec(lvec *slv, long value)
{
  /* If you just want to append an element, use add_to_lvec() instead. */
  int insert_index;
  insert_index = find_index_in_slvec(slv, value);
  if (insert_index >= lvec_size(slv)) add_to_lvec(slv, value);
  else if (value != lvec_ref(slv, insert_index)) {
    lvec_insert(slv, insert_index, value);
  }
}

void slvec_remove_value(lvec *slv, long value)
{
  int idx;
  idx = find_index_in_slvec(slv, value);
  if ( (idx < lvec_size(slv)) && (value == lvec_ref(slv, idx)) ) {
    lvec_remove(slv, idx);
  }
}



/***************************************************************************/
/* lvec math and comparison operations                                     */
/***************************************************************************/

void lvec_add(lvec *lv_1, lvec *lv_2, lvec *r_d)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}

lvec *mk_lvec_add(lvec *a, lvec *b)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

void lvec_subtract(lvec *lv_1, lvec *lv_2, lvec *r_d)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}

lvec *mk_lvec_subtract(lvec *a, lvec *b)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

void lvec_scalar_mult(const lvec *lv, int scale, lvec *rlv)
{
  int i;
  for (i=0; i < lvec_size(lv); i++) lvec_set(rlv, i, lvec_ref(lv, i) * scale);
}

lvec *mk_lvec_scalar_mult(lvec *lv, long scale)
{
  lvec *result;
  result = mk_lvec(lvec_size(lv));
  lvec_scalar_mult(lv, scale, result);
  return result;
}

long lvec_sum(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

long lvec_product_orig(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

bool lvec_weakly_dominates(lvec *dx, lvec *dy)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return FALSE;
}

int  lvec_count_overlap(lvec *a, lvec *b) /* count entries found in both */
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

int  lvec_count_nonmatch(const lvec *x1, const lvec *x2) /* not overlap */
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

bool lvec_equal(const lvec *a, const lvec *b)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return FALSE;
}

bool slvec_equal(const lvec *slva, const lvec *slvb)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return FALSE;
}

bool lvec_array_equal(lvec_array *lva1, lvec_array *lva2)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return FALSE;
}

void lvec_union(lvec *v1, lvec *r_v2) /* union has no duplicates */
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}

lvec *mk_lvec_union(lvec *v1, lvec *v2)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_lvec_union_ordered(lvec *v1, lvec *v2) /* inputs must be ordered */
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_slvec_union(const lvec *slva,const lvec *slvb)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_lvec_intersection(lvec *a, lvec *b)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_slvec_intersection(const lvec *slva, const lvec *slvb)
{
  lvec *result;
  int sizea, sizeb, ai, bi;

  debugger_assert_is_slvec(slva);
  debugger_assert_is_slvec(slvb);

  result = mk_lvec(0);
  ai = 0;
  bi = 0;
  sizea = lvec_size( slva);
  sizeb = lvec_size( slvb);
  while ( (ai < sizea) && (bi < sizeb) ) {
    while ( (ai < sizea) && (lvec_ref(slva, ai) < lvec_ref(slvb, bi))) ai += 1;
    if ( ai < sizea ) {
      while ( (bi < sizeb) && lvec_ref(slvb, bi) < lvec_ref(slva, ai)) bi += 1;
      if ( (bi < sizeb) && (lvec_ref(slva, ai) == lvec_ref(slvb, bi))) {
	add_to_lvec(result, lvec_ref(slva, ai));
	ai += 1;
	bi += 1;
      }
    }
  }
  debugger_assert_is_slvec(result);
  return result;
}

int  size_of_slvec_intersection(const lvec *slva, const lvec *slvb)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return 0;
}

bool slvec_disjoint(lvec *slva,lvec *slvb)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return FALSE;
}

bool slvec_is_subset(const lvec *slva, const lvec *slvb)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return FALSE;
}

bool slvec_strict_subset(const lvec *slva, const lvec *slvb)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return FALSE;
}

lvec *mk_lvec_diff_ordered(lvec *v1, lvec *v2)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_slvec_difference(const lvec *slva,const lvec *slvb)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

/* Returns {0,...,size_of_everything-1} \ slva. */
lvec *mk_slvec_complement( const lvec *slva, int size_of_everything)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_lvec_sort(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

void lvec_sort(lvec *dv, lvec *r_dv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}

void shuffle_lvec(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}


/***************************************************************************/
/* lvec file operations (including printing to screen, etc.)               */
/***************************************************************************/

void fprintf_lvec(FILE *s, char *m1, const lvec *lv, char *m2)
{
  if ( lv == NULL ) fprintf(s,"%s = (lvec *)NULL%s", m1, m2);
  else {
    char buff[256];
    check_lvec_code(lv, "fprintf_lvec");

    /* Modified so that we don't cause a seg fault when m1 is bigger than
       the buffer - WKW*/
    if(strlen(m1) <= 255) strncpy(buff, m1, strlen(m1)+1);
    else {
      strncpy(buff, m1, sizeof(buff));
      buff[255] = '\0';
    }
    fprintf_longs(s, buff, lv->larr, lv->size, m2);
  }
}

void prlvec(lvec *lv)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}

void fprintf_lvec_array (FILE *s, char *m1, lvec_array *lvecarr, char *m2)
{
  if ( lvec_array_size(lvecarr) == 0 ) {
    fprintf(s,"%s = <lvec_array with zero entries>%s",m1,m2);
  }
  else {
    int i;
    for ( i = 0 ; i < lvec_array_size(lvecarr) ; i++ )
    {
      char buff[100];
      lvec *lv = lvec_array_ref(lvecarr, i);
      sprintf(buff, "%s[%2d]", m1, i);
      if ( lv == NULL ) fprintf(s, "%s = NULL%s", buff, m2);
      else fprintf_lvec(s, buff, lv, m2);
    }
  }
}


void save_lvec_to_stream(FILE *s, const lvec *v)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}


/* Return NULL on failure */
lvec *mk_lvec_from_stream(FILE *s, char **r_errmess)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

lvec *mk_lvec_from_filename(const char *filename, char **r_errmess)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

/* Abort on failure */
void save_lvec_to_filename(const char *filename, const lvec *x)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return;
}

lvec *mk_lvec_from_filename_simple(const char *filename)
{
  char msg[500];
  sprintf( msg, "%s:%d:  this function is not yet implemented.",
	   __FILE__, __LINE__);
  my_error( msg);
  return NULL;
}

