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

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

#ifndef AMLV_H
#define AMLV_H

#include "standard.h"
#include "ambs.h"
#include "am_string_array.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.
*/

typedef struct lvec_struct
{
  int  lvec_code;
  int  array_size;
  int  size;
  long *larr;
} lvec, *lvec_ptr;

typedef struct lvec_array_struct
{
  int  size;
  int  array_size;
  lvec **array;
} lvec_array, *lvec_array_ptr;



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

lvec *mk_lvec(int size);
void free_lvec(lvec *lv);

lvec *mk_sequence_lvec(long start_value, long end_value);
lvec *mk_identity_lvec(int size);

lvec *mk_constant_lvec(int size, long value);
lvec *mk_zero_lvec(int size);
lvec *mk_lvec_1(long x0);
lvec *mk_lvec_2(long x0, long x1);
lvec *mk_lvec_3(long x0, long x1, long x2);
lvec *mk_lvec_4(long x0, long x1, long x2, long x3);
lvec *mk_lvec_5(long x0, long x1, long x2, long x3, long x4);
lvec *mk_lvec_6(long x0, long x1, long x2, long x3, long x4, long x5);

void lvec_malloc_report(void);

/* A slvec is sorted and has no duplicates */
lvec *mk_slvec_1(long v1);
lvec *mk_slvec_2(long v1, long v2);
lvec *mk_slvec_3(long v1, long v2, long v3);
lvec *mk_slvec_4(long v1, long v2, long v3, long v4);
lvec *mk_slvec_5(long v1, long v2, long v3, long v4, long v5);

lvec_array *mk_empty_lvec_array (void);
lvec_array *mk_copy_lvec_array (lvec_array *lvecarr);
lvec_array *mk_array_of_empty_lvecs(int size);
void free_lvec_array (lvec_array *lvecarr);



/***************************************************************************/
/* 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);

lvec *mk_lvec_from_file(FILE *fp, char **r_errmess);

/* A slvec is sorted and has no duplicates */
lvec *mk_add_to_slvec(lvec *slv,long value);
lvec *mk_identity_slvec(int size);

lvec_array *mk_transpose_lvec_array( lvec_array *lva );
lvec_array *mk_lvec_array_subset(lvec_array *lva, ivec *rows);

lvec *mk_reverse_lvec(lvec *x);
lvec *mk_indices_of_sorted_lvec(lvec *v);



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

void copy_lvec_subset(const lvec *lv, int start, int size, lvec *r_lv);
void copy_lvec(const lvec *lv, lvec *r_lv);

lvec *mk_lvec_from_larr(long *larr, int size);
long *mk_larr_from_lvec(lvec *lv);
lvec *mk_copy_lvec_subset(lvec *lv, int start, int size);
lvec *mk_copy_lvec(const lvec *lv);
string_array *mk_string_array_from_lvec(lvec *lv);
char *mk_string_from_lvec(lvec *lv);
lvec *mk_lvec_from_lvec_array(lvec_array *lva);
lvec *mk_slvec_from_lvec(lvec *lv);
lvec *mk_lvec_from_string(char *s);
/* 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);
/* Returns lvec of size lvec_size(rows) in which
    result[i] = x[rows[i]] */
lvec *mk_lvec_subset(lvec *x, ivec *rows);



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

long safe_lvec_ref(const lvec *lv, int i);
void safe_lvec_increment(lvec *lv, int i, long value);
void copy_larr_to_lvec(long *larr, int size, lvec *r_lv);
void constant_lvec(lvec *lv, long value);
void zero_lvec(lvec *lv);
#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);


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

void safe_lvec_set(lvec *lv, int i, long value);
void copy_lvec_to_larr(lvec *lv, long *larr);
#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 element summary functions                                          */
/***************************************************************************/

int lvec_num_of_given_value(lvec *lv, long value);
int lvec_num_zero_entries(lvec *lv);
int lvec_num_nonzero_entries(lvec *lv);
int lvec_min(const lvec *lv);
int lvec_max(const lvec *lv);
int lvec_argmin(const lvec *lv);
int lvec_argmax(const lvec *lv);
int  find_index_in_lvec(const lvec *lv, long value); /* -1 => not found => */
ivec *find_all_in_lvec(const lvec *lv, long value); /*empty ivec => not found*/
/* Starts at index=hint, works outward.  -1 => not found */
int  find_index_in_lvec_hint(const lvec *lv, long value, int hint);
int  find_index_in_sorted_lvec(lvec *slv, long val); /* -1 => failure*/
bool is_in_lvec (lvec *lv, long value);
int  safe_lvec_size(const lvec *lv);
int  lvec_array_size (lvec_array *lvecarr);
int  index_of_longest_lvec(lvec_array *lva);
bool is_slvec(const lvec *lv);
int  slvec_size(const lvec *slv);
long slvec_min(const lvec *slv);
long slvec_max(const lvec *slv);
int  find_index_in_slvec(const lvec *slv, long val); /* -1 => failure*/
int  index_in_slvec(const lvec *slv, long value); /* -1 => not found */
bool is_in_slvec(const lvec *slv, long value);


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

void lvec_remove(lvec *lv, int idx);
void lvec_remove_last_element(lvec *lv);
void lvec_remove_last_n_elements( lvec *lv, int n);
void lvec_remove_value(lvec *lv,int val); /* Removes all occurances of val */
void add_to_lvec(lvec *lv, int new_val);
void add_to_sorted_lvec(lvec *slv, int val);
void lvec_insert(lvec *lv, int idx, long val); /* iv_after[index] = val */
void append_lvec_to_lvec(lvec *x, lvec *y);

#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);

void lvec_array_remove(lvec_array *lva,int idx);
void lvec_array_remove_last_element( lvec_array *lva);
void lvec_array_remove_last_n_elements( lvec_array *lva, int n);

void add_to_slvec(lvec *slv, long value);
void slvec_remove_value(lvec *slv, long value);


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

void lvec_add(lvec *lv_1, lvec *lv_2, lvec *r_d);
lvec *mk_lvec_add(lvec *a, lvec *b);
void lvec_subtract(lvec *lv_1, lvec *lv_2, lvec *r_d);
lvec *mk_lvec_subtract(lvec *a, lvec *b);
void lvec_scalar_mult(const lvec *lv, int scale, lvec *rlv);
lvec *mk_lvec_scalar_mult(lvec *lv, long scale);

long lvec_sum(lvec *lv);
long lvec_product_orig(lvec *lv);
bool lvec_weakly_dominates(lvec *dx, lvec *dy);
int  lvec_count_overlap(lvec *a, lvec *b); /* count entries found in both */
int  lvec_count_nonmatch(const lvec *x1, const lvec *x2); /* not overlap */

bool lvec_equal(const lvec *a, const lvec *b);
bool slvec_equal(const lvec *slva, const lvec *slvb);
bool lvec_array_equal(lvec_array *lva1, lvec_array *lva2);

void lvec_union(lvec *v1, lvec *r_v2); /* union has no duplicates */
lvec *mk_lvec_union(lvec *v1, lvec *v2);
lvec *mk_lvec_union_ordered(lvec *v1, lvec *v2); /* inputs must be ordered */
lvec *mk_slvec_union(const lvec *slva,const lvec *slvb);
lvec *mk_lvec_intersection(lvec *a, lvec *b);
lvec *mk_slvec_intersection(const lvec *slva,const lvec *slvb);
int  size_of_slvec_intersection(const lvec *slva, const lvec *slvb);
bool slvec_disjoint(lvec *slva,lvec *slvb);
bool slvec_is_subset(const lvec *slva, const lvec *slvb);
bool slvec_strict_subset(const lvec *slva, const lvec *slvb);
lvec *mk_lvec_diff_ordered(lvec *v1, lvec *v2);
lvec *mk_slvec_difference(const lvec *slva,const lvec *slvb);
/* Returns {0,...,size_of_everything-1} \ slva. */
lvec *mk_slvec_complement( const lvec *slva, int size_of_everything);

lvec *mk_lvec_sort(lvec *lv);
void lvec_sort(lvec *dv, lvec *r_dv);
void shuffle_lvec(lvec *lv);

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

void fprintf_lvec_array (FILE *s, char *m1, lvec_array *lvecarr, char *m2);
void prlvec(lvec *lv);
void fprintf_lvec(FILE *s, char *m1, const lvec *lv, char *m2);


void save_lvec_to_stream(FILE *s, const lvec *v);

/* Return NULL on failure */
lvec *mk_lvec_from_stream(FILE *s, char **r_errmess);
lvec *mk_lvec_from_filename(const char *filename, char **r_errmess);

/* Abort on failure */
void save_lvec_to_filename(const char *filename, const lvec *x);
lvec *mk_lvec_from_filename_simple(const char *filename);


/***************************************************************************/
/* lvec miscellany                                                         */
/***************************************************************************/

#ifdef AMFAST

#define lvec_ref(lv,i) ((lv)->larr[i])
#define lvec_set(lv,i,v) ((lv)->larr[i] = (v))
#define lvec_increment(lv,i,v) ((lv)->larr[i] += (v))
#define lvec_size(lv) ((lv)->size)
#define lvec_array_ref(lva,i) ((lva)->array[i])

#else /* Not AMFAST */

#define lvec_ref(lv,i) (safe_lvec_ref(lv, i))
#define lvec_set(lv,i,v) (safe_lvec_set(lv, i, v))
#define lvec_increment(lv,i,v) (safe_lvec_increment(lv, i, v))
#define lvec_size(lv) (safe_lvec_size(lv))
#define lvec_array_ref(lva,i) safe_lvec_array_ref(lva,i)

#endif /* #ifdef AMFAST */


#endif /* #ifndef AMLV_H */

