/* lp_lm.c
 * Neil Moore <neil@cs.uky.edu>
 * 30 Mar 1999
 *
 * Part of liblp.  See COPYRIGHT for copyright information.
 */
#include <stdlib.h>
#include <lp.h>
#include <lp_lists.h>
#include <lp_util.h>
#include <lp_lm.h>

int *do_compute_dcl_rel(struct lp *p, struct lp_rlist **depends, int *pbs,
			 int *M, struct lp_atom **stack, int sp);
static int *do_compute_dcl(struct lp *p, struct lp_rlist **depends,
			  int *pbs, int *M);

/* Compute the least model of a program p.  Rules with negative bodies
 * are ignored.
 */
int *lp_lm(struct lp *p) 
{
	struct lp_rlist **depends;
	int *pbsize;
	int *result;
	int i;
	
	depends = lp_depends(p);
	pbsize = lp_possizes(p);

	result = do_compute_dcl(p,depends,pbsize,NULL);

	for(i=0; i<p->natoms; i++)
		lp_rl_free(depends[i]);

	free(depends);
	free(pbsize);
	return result;
}


/* Compute the least model of a program.  This is an internal function,
 * called by lp_lm().
 *
 */
int *do_compute_dcl(struct lp *p, struct lp_rlist **depends, int *pbs, int *M)
{
	int i;
	int *inmodel;
	int sp = 0;
	struct lp_atom **stack = lp_malloc(sizeof(struct lp_atom *) * p->size);
	
	for(i=0; i<p->nrules; i++)
		if(pbs[i] == 0 && p->rules[i].nneg == 0)
			stack[sp++] = p->rules[i].head;

	inmodel = do_compute_dcl_rel(p, depends, pbs, M, stack, sp);

	free(stack);
	return inmodel;
}


int *do_compute_dcl_rel(struct lp *p, struct lp_rlist **depends, int *pbs,
			int *M, struct lp_atom **stack, int sp) 
{
	int *inmodel;
	struct lp_rlist *j;
	
	inmodel = lp_calloc(p->natoms, sizeof(int));
	
	/* pop */
	while(sp != 0) {
		int apos = lp_apos(p,stack[--sp]);

		if(M != NULL && M[apos] == LP_L_TRUE)
			inmodel[apos] = 1;
		if(inmodel[apos])
			continue;
		inmodel[apos] = 1;

		for(j=depends[apos]; j!=NULL; j=j->next)
			if(--pbs[lp_rpos(p, j->rule)] == 0 && j->rule->nneg == 0)
				stack[sp++] = j->rule->head;
	}

	return inmodel;
}
