/*
   File:        dex.h
   Author:      Andrew W. Moore
   Created:     Fri Jan  8 10:38:18 EST 1999
   Description: Header for Propositional Dexulae

   Copyright 1999, Schenley Park Research, Inc
*/


#ifndef DEX_H
#define DEX_H

#include <time.h>
#include "amut.h"
#include "dsut.h"

#define ATTNUM     0
#define ROW        1
#define MISSING    2
#define RANDOM     3
#define GAUSSIAN   4
#define REALVAL    5
#define SYMBOLVAL  6
#define NOT        7
#define IFTHENELSE 8
#define EQ         9
#define NEQ       10
#define DIVIDE    11
#define TIMES     12
#define POWER     13 /* power(x,y) = x^y */

/* all *P functions take a number(s) in 0-1 and map to another number in 0-1 */
#define ABS	14
#define SQRT	15
#define SIGN	16 /* signum: trinary output: {-1,0,+1} */
#define EXP	17
#define LOG	18 /* natural logarithm */
#define LOG10	19 /* decimal logarithm */
#define LOGP    20 /* log(x*(e-1))+1) */
#define RECP    21 /* 2/(1+x)-1 */
#define EXPP    22 /* (e^x - 1) / (e-1) */
#define NEGP    23 /* -x+1 */
#define PRE	24 /* preceding entry in the data column:
                      pre(attx[k]) = attx[k-1]) for k > 0;
		      pre(attx[0]) = attx[0]; */
#define SUC     25 /* succeding entry: suc(attx[k]) = attx[k+1])
		      for k < numrows; pre(attx[numrows]) = attx[numrows]; */
#define DERIV	26 /* first derivative: deriv(y,x) = dy/dx */
#define RANKS   27 /* computes ranks of the attribute values
		      (intended for real attributes) */
#define SRANKS  28 /* computes ranks of symbolic attribute w.r.t some real
		      attribute */

#define MINUS     29
#define PLUS      30
#define PLUSP     31  /* (x+y)/2 */
#define GEQ       32
#define LEQ       33
#define GREATER   34
#define LESSTHAN  35
#define AND       36
#define OR        37
#define IMPLIES   38
#define IFF       39

#define YEAR      40  /* retrieves year from a date field */
#define YEARDAYS  41  /* retrieves number of days elapsed this year */
#define DAYS      42  /* Number of days since 1st Jan 1900 */
#define DAYFRAC   43  /* retrieves fraction of day (0 to 1) from time field */
#define ROUND     44

#define SIN       45
#define COS       46

#define MOD       47  /* use % sign to mean mod */

#define NUM_DTYPES 48

typedef struct dex
{
  int symbol_type;   /* If denotes the value of a symbolic attribute,
                        this field says what symbolic attribute it denotes
                        the value of */
  int dtype;
  int attnum;
  double realval;
  int symbolval;
  struct dex *arg1;
  struct dex *arg2;
  struct dex *arg3;
} dex;

/* Returns a string with the name of the dtype */
char *dtype_to_name(int dtype);

/* Returns the dtype, given the name,
   returns -1 if no such dtype */

/* Declared but not defined - sir 9/6/2000
int name_to_dtype(char *name); */

/* Create an empty dex of dtype */
dex *mk_empty_dex(int dtype);

/* Returns the followin arguments of the dex */
int dex_dtype(dex *dx);
/* Declared but not defined - sir 9/6/2000
dex *dxx_arg1(dex *dx);
dex *dxx_arg2(dex *dx); */
int dex_attnum(dex *dx);

/* Makes a copy of f and recursively makes a copy of all its subcomponents
   and returns the result. */
dex *mk_copy_dex(dex *dx);


/* All of the cons_xxx_dex functions make and return a new dexula,
   usually from other subdexulae. For example, cons_or_dex(a,b)
   makes (am_malloc's) and returns a new dex denoting "a v b".

   Here's a very important memory management note (and the main reason
   that prima-donna programmers get upset about not having garbage
   collection).

   The cons_xxx_dex(a,b) use the pointers to a and b directly: after
   making this call, the
   programmer should NEVER TOUCH OR FREE dex *a or dex *b again. The
   programmer should eventually free the result of this call, and then
   indirectly a and b will be recursively freed. 

   If you'd prefer to make a dex in which the subcomponents are COPIED
   IN RECURSIVELY, call mk_xxx_dex(a,b) instead. Then the result will
   contain a complete recursive copy of a and or b instead. And that means
   that the programmer can change a or b without accidently affecting
   result. The programmer must eventually deal with freeing a and b, AND
   the result. */

dex *cons_binary_dex(dex *a,dex *b,int dtype);
dex *cons_trinary_dex(dex *a,dex *b,dex *c,int dtype);
dex *cons_unary_dex(dex *a,int dtype);

/* There may be a lot of functions here that should be made static. I'll
 * figure it out later -- better to wait a bit than to break stuff. -- Pat */
dex *mk_binary_dex(dex *a,dex *b,int dtype);
dex *mk_unary_dex(dex *a,int dtype);
dex *cons_abs_dex(dex *a);
dex *mk_abs_dex(dex *a);
dex *cons_sqrt_dex(dex *a);
dex *mk_sqrt_dex(dex *a);
dex *cons_sign_dex(dex *a);
dex *mk_sign_dex(dex *a);
dex *cons_exp_dex(dex *a);
dex *mk_exp_dex(dex *a);
dex *cons_log_dex(dex *a);
dex *mk_log_dex(dex *a);
dex *cons_log10_dex(dex *a);
dex *mk_log10_dex(dex *a);
dex *cons_sin_dex(dex *a);
dex *mk_sin_dex(dex *a);
dex *cons_cos_dex(dex *a);
dex *mk_cos_dex(dex *a);
dex *cons_pre_dex(dex *a);
dex *mk_pre_dex(dex *a);
dex *cons_suc_dex(dex *a);
dex *mk_suc_dex(dex *a);
dex *cons_deriv_dex(dex *y,dex *x);
dex *mk_deriv_dex(dex *y,dex *x);
dex *cons_ranks_dex(dex *a);
dex *mk_ranks_dex(dex *a);
dex *mk_sranks_dex(dex *x, dex *y);
dex *mk_year_dex(dex *a);
dex *mk_yeardays_dex(dex *a);
dex *mk_days_dex(dex *a);
dex *mk_dayfrac_dex(dex *a);
dex *mk_round_dex(dex *a);
dex *cons_sranks_dex(dex *x, dex *y);
bool eq_token(string_array *tokens,int idx,char *key); /* XXX Belongs elsewhere */
dex *dex_arg1(dex *dx);
dex *dex_arg2(dex *dx);
dex *dex_arg3(dex *dx);
double dex_realval(dex *dx);
char *symbol_type_to_name(datset *ds,int symbol_type);
dex *mk_parse_part(datset *ds,string_array *tokens,int *idx, int dtype,int symbol_type,char **r_errmess);


void add_to_string_array_start(char *s,string_array *sa); /* XXX Belongs elsewhere */
void parenthesize_sa(string_array *sa); /* NOOOOOO */
string_array *mk_append_string_arrays(string_array *a,string_array *b);
double safe_divide(double v1,double v2,bool *r_missing);
double year_from_date_string(char *s);
void clear_tm(struct tm *a);
int tm_time_diff(struct tm *a, struct tm *b); /* I've implemented this elsewhere because it was in the wrong place. Argh! */
int tm_year_days(struct tm *a);
double yeardays(int year, int month, int day);
double days_fn(int year, int month, int day);
double yeardays_from_date_string(char *s, bool american);
double days_from_date_string(char *s, bool american);
double dayfrac_from_time_string(char *s);






/* Makes "a <=> b" dex using the pointers to a and b directly. */
dex *cons_iff_dex(dex *a,dex *b);

/* Makes and returns a new dexula: "a <=> b". Note that
   it makes a COPY of its two arguments, so that afterwards a and b
   can be changed or freed without an effect on result of this call. */
dex *mk_iff_dex(dex *a,dex *b);

/* Makes "a => b" dex using the pointers to a and b directly. */
dex *cons_implies_dex(dex *a,dex *b);

/* Makes "a => b" dex, including COPIES of a and b */
dex *mk_implies_dex(dex *a,dex *b);

/* Makes "a v b" dex using the pointers to a and b directly. */
dex *cons_or_dex(dex *a,dex *b);

/* Makes "a v b" dex, including COPIES of a and b */
dex *mk_or_dex(dex *a,dex *b);

/* Makes "a ^ b" dex using the pointers to a and b directly. */
dex *cons_and_dex(dex *a,dex *b);

/* Makes "a ^ b" dex, including COPIES of a and b */
dex *mk_and_dex(dex *a,dex *b);

/* Makes "~ a" dex using the pointer to a directly. */
/* Declared but not defined - sir 9/6/2000
dex *cons_not_dex(dex *a);

/ * Makes "~ a" dex, including a COPY of a * /
dex *mk_not_dex(dex *a); */

/* Parses the string and builds a dexula */
dex *mk_parse_dex(datset *ds,int attnum,string_array *tokens,char **r_errmess);

/* Warning, this recursively frees all sub-components of the dex too. */
void free_dex(dex *dx);

/* Returns an array of strings corresponding to the dex */
string_array *mk_string_array_from_dex(datset *ds,dex *dx);

/* Returns a string corresponding to the dex */
char *mk_string_from_dex(datset *ds,dex *dx);

/* Prints the dex, on a FILE or on the screen */
void fprint_dex(FILE *s,datset *ds,dex *dx);
void print_dex(datset *ds,dex *dx);

double eval_dex(datset *ds,dex *dx,int row,bool *r_missing);

void apply_dex_to_dset(datset *ds,int attnum,dex *dx);

/* Returns sivec of all attnums appearing in dex */
ivec *mk_dex_attnums(dex *dx);

#endif /* #ifndef DEX_H */

