/* lp.h
 * Neil Moore <neil@cs.uky.edu>
 * 15 Nov 1999
 *
 * Part of liblp.  See COPYRIGHT for copyright information.
 */
#ifndef _LP_H_INCLUDED
#define _LP_H_INCLUDED

#include <lp_lists.h>

/* The maximum length of atom names */
#define LP_ATOMLEN 128
/* The maximum positive and negative body sizes */
#define LP_MAXPOS  15
#define LP_MAXNEG  15

/* Three-valued truth values. */
#define LP_L_UNKNOWN 0
#define LP_L_TRUE 1
#define LP_L_FALSE -1

/* Rule types (from lp_classify_rule()). */
#define LP_R_NORMAL        0 /* none of the following */
#define LP_R_FACT          1 /* empty body */
#define LP_R_HORN          2 /* empty negative body */
#define LP_R_NEGATIVE      3 /* empty positive body */
#define LP_R_KILLING       4 /* head appears negatively in body always */
#define LP_R_LOCAL_KILLING 5 /* head appears negatively in body in this rule */

/* A logic-programming rule.
 */
struct lp_rule {
	/* A pointer to this rule's head atom */
	struct lp_atom *head;
	
	/* The size of the positive body */
	int npos;
	/* An array of pointers to the positive body atoms */
	struct lp_atom *pos[LP_MAXPOS];
	/* The size of the negative body */
	int nneg;
	/* An array of pointers to the negative body atoms */
	struct lp_atom *neg[LP_MAXNEG];

	/* The rule type (not set or used by liblp) */
	int type;
};

/* A logic-programming atom.
 */
struct lp_atom {
	char name[LP_ATOMLEN+1];
};

/* A logic program with additional information.
 */
struct lp {
	/* The number of atoms */
	int natoms;
	/* The number of rules */
	int nrules;	
	/* The program size.  Defined as the sum of the body sizes of each
	 * rules, plus the number of rules.
	 */
	int size;

	/* An array of atoms */
	struct lp_atom *atoms;
	/* An array of rules */
	struct lp_rule *rules;

	/* The number of positive requirements. */
	int nposreq;
	/* An array of pointers to atoms; atoms in posreq must appear in
	 * all stable models of the program.
	 */
	struct lp_atom **posreq;
	/* The number of negative requirements */
	int nnegreq;
	/* An array of pointers to atoms; atoms in negreq must appear in
	 * no stable models of the program.
	 */
	struct lp_atom **negreq;

	/* The number of models to generate.  0 = all. */
	int nmodels;
};


/* Return a string indicating the liblp version number */
const char *lp_version(void);
/* Return a string indicating the lpsms version number */
const char *lp_sms_version(void);

#ifdef USE_REAL_LP_APOS_AND_RPOS
/* Compute the position of an atom in a program */
int lp_apos(struct lp *p, struct lp_atom *a);
/* Compute the position of a rule in a program */
int lp_rpos(struct lp *p, struct lp_rule *r);
#else  /* !defined(USE_REAL_LP_APOS_AND_RPOS) */
# define lp_apos(p,a) ((int)((a)-(p->atoms)))
# define lp_rpos(p,r) ((int)((r)-(p->rules)))
#endif /* USE_REAL_LP_APOS_AND_RPOS */

/* Initialise a program */
void lp_init_lp(struct lp *p, int nrules, int natoms, int size);
/* Free a program */
void lp_free_lp(struct lp *p);
/* Copy a program, allocating memory for the copy */
struct lp *lp_copy_lp(struct lp *p);
/* Copy a program except for rules, allocating memory for the copy */
struct lp *lp_copy_lp_basic(struct lp *p);

int lp_simplify_lp(struct lp *p);

/* Classify a rule as one of the LP_R_* types */
int lp_classify_rule(struct lp *p, struct lp_rule *r);
/* As above, but do not perform global killing atom tests. */
int lp_classify_rule_local(struct lp *p, struct lp_rule *r);
/* Is a rule a fact? */
int lp_is_fact(struct lp *p, struct lp_rule *r);
/* Is a rule a horn clause? */
int lp_is_horn(struct lp *p, struct lp_rule *r);
/* Is a rule a local killing rule? */
int lp_is_local_killing(struct lp *p, struct lp_rule *r);
/* Is a rule a (global) killing rule? */
int lp_is_killing(struct lp *p, struct lp_rule *r);

/* construct dependency lists */
struct lp_rlist **lp_headof(struct lp *p);
struct lp_rlist **lp_depends(struct lp *p);
struct lp_rlist **lp_posdepends(struct lp *p);
struct lp_rlist **lp_negdepends(struct lp *p);

/* count number of times each atom appears in a head */
int *lp_count_head(struct lp *p);

/* count body sizes for each rule */
int *lp_bodysizes(struct lp *p);
int *lp_possizes(struct lp *p);
int *lp_negsizes(struct lp *p);

#endif /* _LP_H_INCLUDED */
