This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/OPTYap/tab.tries.c
2010-04-16 03:07:37 +01:00

1466 lines
49 KiB
C

/************************************************************************
** **
** The YapTab/YapOr/OPTYap systems **
** **
** YapTab extends the Yap Prolog engine to support sequential tabling **
** YapOr extends the Yap Prolog engine to support or-parallelism **
** OPTYap extends the Yap Prolog engine to support or-parallel tabling **
** **
** **
** Yap Prolog was developed at University of Porto, Portugal **
** **
************************************************************************/
/************************************
** Includes & Prototypes **
************************************/
#include "Yap.h"
#ifdef TABLING
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif /* HAVE_STRING_H */
#include "Yatom.h"
#include "YapHeap.h"
#include "yapio.h"
#include "tab.macros.h"
static inline sg_node_ptr subgoal_trie_check_insert_entry(tab_ent_ptr, sg_node_ptr, Term);
static inline ans_node_ptr answer_trie_check_insert_entry(sg_fr_ptr, ans_node_ptr, Term, int);
static inline sg_node_ptr subgoal_search_loop(tab_ent_ptr, sg_node_ptr, Term, int *, CELL **);
static inline ans_node_ptr answer_search_loop(sg_fr_ptr, ans_node_ptr, Term, int *);
static inline CELL *load_answer_loop(ans_node_ptr);
#ifdef GLOBAL_TRIE
static inline gt_node_ptr global_trie_check_insert_entry(gt_node_ptr, Term);
static inline sg_node_ptr subgoal_trie_check_insert_gt_entry(tab_ent_ptr, sg_node_ptr, Term);
static inline ans_node_ptr answer_trie_check_insert_gt_entry(sg_fr_ptr, ans_node_ptr, Term, int);
#ifdef GLOBAL_TRIE_FOR_TERMS
static inline gt_node_ptr subgoal_search_loop_gt_term(Term, int *, CELL **);
static inline gt_node_ptr answer_search_loop_gt_term(Term, int *);
#elif GLOBAL_TRIE_FOR_SUBTERMS
static inline gt_node_ptr global_trie_check_insert_gt_entry(gt_node_ptr, Term);
static inline gt_node_ptr subgoal_search_loop_gt_subterm(Term, int *, CELL **, CELL *);
static inline gt_node_ptr answer_search_loop_gt_subterm(Term, int *, CELL *);
#endif /* GLOBAL_TRIE_MODE */
static inline CELL *load_substitution_loop(gt_node_ptr, int *, CELL *);
static inline CELL *exec_substitution_loop(gt_node_ptr, CELL **, CELL *);
#ifdef GLOBAL_TRIE_FOR_TERMS
static void free_global_trie_branch(gt_node_ptr);
#elif GLOBAL_TRIE_FOR_SUBTERMS
static void free_global_trie_branch(gt_node_ptr, int);
#endif /* GLOBAL_TRIE_MODE */
static void traverse_global_trie(gt_node_ptr, char *, int, int *, int, int);
static void traverse_global_trie_for_term(gt_node_ptr, char *, int *, int *, int *, int);
#endif /* GLOBAL_TRIE */
static void traverse_subgoal_trie(sg_node_ptr, char *, int, int *, int, int);
static void traverse_answer_trie(ans_node_ptr, char *, int, int *, int, int, int);
static inline void traverse_trie_node(Term, char *, int *, int *, int *, int);
#ifdef YAPOR
#ifdef TABLING_INNER_CUTS
static int update_answer_trie_branch(ans_node_ptr, ans_node_ptr);
#else /* YAPOR && ! TABLING_INNER_CUTS */
static int update_answer_trie_branch(ans_node_ptr);
#endif
#else /* ! YAPOR */
static void update_answer_trie_branch(ans_node_ptr, int);
#endif
/*******************************
** Structs & Macros **
*******************************/
static struct trie_statistics{
int show;
long subgoals;
long subgoals_incomplete;
long subgoal_trie_nodes;
long answers;
#ifdef TABLING_INNER_CUTS
long answers_pruned;
#endif /* TABLING_INNER_CUTS */
long answers_true;
long answers_no;
long answer_trie_nodes;
#ifdef GLOBAL_TRIE
long global_trie_terms;
long global_trie_nodes;
long global_trie_references;
#endif /* GLOBAL_TRIE */
} trie_stats;
#define TrStat_show trie_stats.show
#define TrStat_subgoals trie_stats.subgoals
#define TrStat_sg_incomplete trie_stats.subgoals_incomplete
#define TrStat_sg_nodes trie_stats.subgoal_trie_nodes
#define TrStat_answers trie_stats.answers
#define TrStat_answers_true trie_stats.answers_true
#define TrStat_answers_no trie_stats.answers_no
#define TrStat_answers_pruned trie_stats.answers_pruned
#define TrStat_ans_nodes trie_stats.answer_trie_nodes
#define TrStat_gt_terms trie_stats.global_trie_terms
#define TrStat_gt_nodes trie_stats.global_trie_nodes
#define TrStat_gt_refs trie_stats.global_trie_references
#define SHOW_TABLE_STR_ARRAY_SIZE 100000
#define SHOW_TABLE_ARITY_ARRAY_SIZE 10000
#define SHOW_TABLE_STRUCTURE(MESG, ARGS...) \
if (TrStat_show == SHOW_MODE_STRUCTURE) \
fprintf(Yap_stdout, MESG, ##ARGS)
#ifndef GLOBAL_TRIE
#define DECREMENT_GLOBAL_TRIE_REFERENCE(REF)
#else /* GLOBAL_TRIE */
#define DECREMENT_GLOBAL_TRIE_REFERENCE(REF) \
if (IsVarTerm(REF) && REF > VarIndexOfTableTerm(MAX_TABLE_VARS)) { \
register gt_node_ptr gt_node = (gt_node_ptr) (REF); \
TrNode_child(gt_node) = (gt_node_ptr) ((unsigned long int) TrNode_child(gt_node) - 1); \
if (TrNode_child(gt_node) == 0) \
FREE_GLOBAL_TRIE_BRANCH(gt_node,TRAVERSE_MODE_NORMAL); \
}
#endif /* GLOBAL_TRIE */
#ifdef GLOBAL_TRIE_FOR_SUBTERMS
#define CHECK_DECREMENT_GLOBAL_TRIE_REFERENCE(REF,MODE) \
if (MODE == TRAVERSE_MODE_NORMAL) \
DECREMENT_GLOBAL_TRIE_REFERENCE(REF)
#define FREE_GLOBAL_TRIE_BRANCH(NODE,MODE) \
free_global_trie_branch(NODE,MODE)
#else
#define CHECK_DECREMENT_GLOBAL_TRIE_REFERENCE(REF,MODE)
#define FREE_GLOBAL_TRIE_BRANCH(NODE,MODE) \
free_global_trie_branch(NODE)
#endif /* GLOBAL_TRIE_FOR_SUBTEMRS */
/******************************
** Local functions **
******************************/
#define INCLUDE_SUBGOAL_TRIE_CHECK_INSERT /* subgoal_trie_check_insert_entry */
#define INCLUDE_ANSWER_TRIE_CHECK_INSERT /* answer_trie_check_insert_entry */
#ifdef GLOBAL_TRIE
#define INCLUDE_GLOBAL_TRIE_CHECK_INSERT /* global_trie_check_insert_entry */
#endif /* GLOBAL_TRIE */
#define INCLUDE_SUBGOAL_SEARCH_LOOP /* subgoal_search_loop */
#define INCLUDE_ANSWER_SEARCH_LOOP /* answer_search_loop */
#define INCLUDE_LOAD_ANSWER_LOOP /* load_answer_loop */
#include "tab.tries.i"
#undef INCLUDE_SUBGOAL_TRIE_CHECK_INSERT
#undef INCLUDE_ANSWER_TRIE_CHECK_INSERT
#undef INCLUDE_GLOBAL_TRIE_CHECK_INSERT
#undef INCLUDE_SUBGOAL_SEARCH_LOOP
#undef INCLUDE_ANSWER_SEARCH_LOOP
#undef INCLUDE_LOAD_ANSWER_LOOP
#ifdef GLOBAL_TRIE
#define MODE_GLOBAL_TRIE_ENTRY
#define MODE_GLOBAL_TRIE_LOOP
#define INCLUDE_SUBGOAL_TRIE_CHECK_INSERT /* subgoal_trie_check_insert_gt_entry */
#define INCLUDE_ANSWER_TRIE_CHECK_INSERT /* answer_trie_check_insert_gt_entry */
#ifdef GLOBAL_TRIE_FOR_SUBTERMS
#define INCLUDE_GLOBAL_TRIE_CHECK_INSERT /* global_trie_check_insert_gt_entry */
#endif /* GLOBAL_TRIE_FOR_SUBTERMS */
#define INCLUDE_SUBGOAL_SEARCH_LOOP /* subgoal_search_loop_gt_(sub)terms */
#define INCLUDE_ANSWER_SEARCH_LOOP /* answer_search_loop_gt_(sub)terms */
#define INCLUDE_LOAD_ANSWER_LOOP /* load_substitution_loop */
#include "tab.tries.i"
#undef MODE_GLOBAL_TRIE_ENTRY
#undef MODE_GLOBAL_TRIE_LOOP
#undef INCLUDE_SUBGOAL_TRIE_CHECK_INSERT
#undef INCLUDE_ANSWER_TRIE_CHECK_INSERT
#undef INCLUDE_GLOBAL_TRIE_CHECK_INSERT
#undef INCLUDE_SUBGOAL_SEARCH_LOOP
#undef INCLUDE_ANSWER_SEARCH_LOOP
#undef INCLUDE_LOAD_ANSWER_LOOP
static inline CELL *exec_substitution_loop(gt_node_ptr current_node, CELL **stack_vars_ptr, CELL *stack_terms) {
/************************************************************************
===========
| |
| ... |
| |
-----------
YENV --> | N+1 | <-- stack_vars
-----------
| VAR_N |
-----------
| ... |
-----------
| VAR_0 |
-----------
| |
| ... |
| |
===========
| |
| ... |
| |
-----------
TR --> | | <-- stack_terms_limit
-----------
| |
| ... |
| |
----------|
| TERM_N | <-- stack_terms
----------| *
| ... | /|\
----------| | stack_terms_pair_offset (TRIE_COMPACT_PAIRS)
| TERM_1 | \|/
=========== *
Yap_TrailTop --> | | <-- stack_terms_base (TRIE_COMPACT_PAIRS)
-----------
************************************************************************/
CELL *stack_vars = *stack_vars_ptr;
CELL *stack_terms_limit = (CELL *) TR;
#ifdef TRIE_COMPACT_PAIRS
#define stack_terms_base ((CELL *) Yap_TrailTop)
int stack_terms_pair_offset = 0;
#endif /* TRIE_COMPACT_PAIRS */
Term t = TrNode_entry(current_node);
current_node = TrNode_parent(current_node);
do {
if (IsVarTerm(t)) {
#ifdef GLOBAL_TRIE_FOR_SUBTERMS
if (t > VarIndexOfTableTerm(MAX_TABLE_VARS)) {
stack_terms = exec_substitution_loop((gt_node_ptr) t, &stack_vars, stack_terms);
} else
#endif /* GLOBAL_TRIE_FOR_SUBTERMS */
{
int var_index = VarIndexOfTableTerm(t);
int vars_arity = *stack_vars;
t = MkVarTerm();
if (var_index >= vars_arity) {
while (vars_arity < var_index) {
*stack_vars-- = 0;
vars_arity++;
}
*stack_vars-- = t;
vars_arity++;
*stack_vars = vars_arity;
} else {
/* do the same as in macro stack_trie_val_instr() */
CELL aux_sub, aux_var, *vars_ptr;
vars_ptr = stack_vars + vars_arity - var_index;
aux_sub = *((CELL *) t);
aux_var = *vars_ptr;
if (aux_var == 0) {
*vars_ptr = t;
} else {
if (aux_sub > aux_var) {
if ((CELL *) aux_sub <= H) {
Bind_Global((CELL *) aux_sub, aux_var);
} else if ((CELL *) aux_var <= H) {
Bind_Local((CELL *) aux_sub, aux_var);
} else {
Bind_Local((CELL *) aux_var, aux_sub);
*vars_ptr = aux_sub;
}
} else {
if ((CELL *) aux_var <= H) {
Bind_Global((CELL *) aux_var, aux_sub);
*vars_ptr = aux_sub;
} else if ((CELL *) aux_sub <= H) {
Bind_Local((CELL *) aux_var, aux_sub);
*vars_ptr = aux_sub;
} else {
Bind_Local((CELL *) aux_sub, aux_var);
}
}
}
}
AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit);
STACK_PUSH_UP(t, stack_terms);
}
} else if (IsAtomOrIntTerm(t)) {
AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit);
STACK_PUSH_UP(t, stack_terms);
} else if (IsPairTerm(t)) {
#ifdef TRIE_COMPACT_PAIRS
if (t == CompactPairInit) {
Term *stack_aux = stack_terms_base - stack_terms_pair_offset;
Term head, tail = STACK_POP_UP(stack_aux);
while (STACK_NOT_EMPTY(stack_aux, stack_terms)) {
head = STACK_POP_UP(stack_aux);
tail = MkPairTerm(head, tail);
}
stack_terms = stack_terms_base - stack_terms_pair_offset;
stack_terms_pair_offset = (int) STACK_POP_DOWN(stack_terms);
STACK_PUSH_UP(tail, stack_terms);
} else { /* CompactPairEndList / CompactPairEndTerm */
Term last;
AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit + 1);
last = STACK_POP_DOWN(stack_terms);
STACK_PUSH_UP(stack_terms_pair_offset, stack_terms);
stack_terms_pair_offset = (int) (stack_terms_base - stack_terms);
if (t == CompactPairEndList)
STACK_PUSH_UP(TermNil, stack_terms);
STACK_PUSH_UP(last, stack_terms);
}
#else
Term head = STACK_POP_DOWN(stack_terms);
Term tail = STACK_POP_DOWN(stack_terms);
t = MkPairTerm(head, tail);
STACK_PUSH_UP(t, stack_terms);
#endif /* TRIE_COMPACT_PAIRS */
} else if (IsApplTerm(t)) {
Functor f = (Functor) RepAppl(t);
if (f == FunctorDouble) {
volatile Float dbl;
volatile Term *t_dbl = (Term *)((void *) &dbl);
t = TrNode_entry(current_node);
current_node = TrNode_parent(current_node);
t_dbl[0] = t;
#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P
t = TrNode_entry(current_node);
current_node = TrNode_parent(current_node);
t_dbl[1] = t;
#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */
current_node = TrNode_parent(current_node);
t = MkFloatTerm(dbl);
} else if (f == FunctorLongInt) {
Int li = TrNode_entry(current_node);
current_node = TrNode_parent(current_node);
current_node = TrNode_parent(current_node);
t = MkLongIntTerm(li);
} else {
int f_arity = ArityOfFunctor(f);
t = Yap_MkApplTerm(f, f_arity, stack_terms);
stack_terms += f_arity;
}
AUX_STACK_CHECK_EXPAND(stack_terms, stack_terms_limit);
STACK_PUSH_UP(t, stack_terms);
}
t = TrNode_entry(current_node);
current_node = TrNode_parent(current_node);
} while (current_node);
*stack_vars_ptr = stack_vars;
return stack_terms;
#ifdef TRIE_COMPACT_PAIRS
#undef stack_terms_base
#endif /* TRIE_COMPACT_PAIRS */
}
#ifdef GLOBAL_TRIE_FOR_TERMS
static void free_global_trie_branch(gt_node_ptr current_node) {
#elif GLOBAL_TRIE_FOR_SUBTERMS
static void free_global_trie_branch(gt_node_ptr current_node, int mode) {
Term t = TrNode_entry(current_node);
#endif
gt_node_ptr parent_node, child_node;
parent_node = TrNode_parent(current_node);
child_node = TrNode_child(parent_node);
if (IS_GLOBAL_TRIE_HASH(child_node)) {
gt_hash_ptr hash = (gt_hash_ptr) child_node;
gt_node_ptr *bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(current_node), Hash_seed(hash)));
int num_nodes = --Hash_num_nodes(hash);
child_node = *bucket;
if (child_node != current_node) {
while (TrNode_next(child_node) != current_node)
child_node = TrNode_next(child_node);
TrNode_next(child_node) = TrNode_next(current_node);
CHECK_DECREMENT_GLOBAL_TRIE_REFERENCE(t,mode);
FREE_GLOBAL_TRIE_NODE(current_node);
} else {
*bucket = TrNode_next(current_node);
CHECK_DECREMENT_GLOBAL_TRIE_REFERENCE(t,mode);
FREE_GLOBAL_TRIE_NODE(current_node);
if (num_nodes == 0) {
FREE_HASH_BUCKETS(Hash_buckets(hash));
FREE_GLOBAL_TRIE_HASH(hash);
if (parent_node != GLOBAL_root_gt) {
#ifdef GLOBAL_TRIE_FOR_SUBTERMS
if (mode == TRAVERSE_MODE_NORMAL) {
if (IsApplTerm(t)) {
Functor f = (Functor) RepAppl(t);
if (f == FunctorDouble)
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_DOUBLE);
else if (f == FunctorLongInt)
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_LONGINT);
else
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_NORMAL);
} else
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_NORMAL);
} else if (mode == TRAVERSE_MODE_LONGINT)
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_LONGINT_END);
else if (mode == TRAVERSE_MODE_DOUBLE)
#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_DOUBLE2);
else if (mode == TRAVERSE_MODE_DOUBLE2)
#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_DOUBLE_END);
else
#endif /* GLOBAL_TRIE_FOR_SUBTERMS */
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_NORMAL);
} else
TrNode_child(parent_node) = NULL;
}
}
} else if (child_node != current_node) {
while (TrNode_next(child_node) != current_node)
child_node = TrNode_next(child_node);
TrNode_next(child_node) = TrNode_next(current_node);
CHECK_DECREMENT_GLOBAL_TRIE_REFERENCE(t,mode);
FREE_GLOBAL_TRIE_NODE(current_node);
} else if (TrNode_next(current_node) == NULL) {
CHECK_DECREMENT_GLOBAL_TRIE_REFERENCE(t,mode);
FREE_GLOBAL_TRIE_NODE(current_node);
if (parent_node != GLOBAL_root_gt) {
#ifdef GLOBAL_TRIE_FOR_SUBTERMS
if (mode == TRAVERSE_MODE_NORMAL) {
if (IsApplTerm(t)) {
Functor f = (Functor) RepAppl(t);
if (f == FunctorDouble)
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_DOUBLE);
else if (f == FunctorLongInt)
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_LONGINT);
else
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_NORMAL);
} else
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_NORMAL);
} else if (mode == TRAVERSE_MODE_LONGINT)
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_LONGINT_END);
else if (mode == TRAVERSE_MODE_DOUBLE)
#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_DOUBLE2);
else if (mode == TRAVERSE_MODE_DOUBLE2)
#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_DOUBLE_END);
else
#endif /* GLOBAL_TRIE_FOR_SUBTERMS */
FREE_GLOBAL_TRIE_BRANCH(parent_node,TRAVERSE_MODE_NORMAL);
} else
TrNode_child(parent_node) = NULL;
} else {
TrNode_child(parent_node) = TrNode_next(current_node);
CHECK_DECREMENT_GLOBAL_TRIE_REFERENCE(t,mode);
FREE_GLOBAL_TRIE_NODE(current_node);
}
return;
}
static void traverse_global_trie(gt_node_ptr current_node, char *str, int str_index, int *arity, int mode, int position) {
int *current_arity = NULL, current_str_index = 0, current_mode = 0;
/* test if hashing */
if (IS_GLOBAL_TRIE_HASH(current_node)) {
gt_node_ptr *bucket, *last_bucket;
gt_hash_ptr hash;
hash = (gt_hash_ptr) current_node;
bucket = Hash_buckets(hash);
last_bucket = bucket + Hash_num_buckets(hash);
current_arity = (int *) malloc(sizeof(int) * (arity[0] + 1));
memcpy(current_arity, arity, sizeof(int) * (arity[0] + 1));
do {
if (*bucket) {
traverse_global_trie(*bucket, str, str_index, arity, mode, TRAVERSE_POSITION_FIRST);
memcpy(arity, current_arity, sizeof(int) * (current_arity[0] + 1));
#ifdef TRIE_COMPACT_PAIRS
if (arity[arity[0]] == -2 && str[str_index - 1] != '[')
str[str_index - 1] = ',';
#else
if (arity[arity[0]] == -1)
str[str_index - 1] = '|';
#endif /* TRIE_COMPACT_PAIRS */
}
} while (++bucket != last_bucket);
free(current_arity);
return;
}
/* save current state if first sibling node */
if (position == TRAVERSE_POSITION_FIRST) {
current_arity = (int *) malloc(sizeof(int) * (arity[0] + 1));
memcpy(current_arity, arity, sizeof(int) * (arity[0] + 1));
current_str_index = str_index;
current_mode = mode;
}
/* process current trie node */
TrStat_gt_nodes++;
traverse_trie_node(TrNode_entry(current_node), str, &str_index, arity, &mode, TRAVERSE_TYPE_SUBGOAL);
/* continue with child node ... */
if (arity[0] != 0 || mode != TRAVERSE_MODE_NORMAL)
traverse_global_trie(TrNode_child(current_node), str, str_index, arity, mode, TRAVERSE_POSITION_FIRST);
/* ... or show term */
else {
TrStat_gt_terms++;
str[str_index] = 0;
SHOW_TABLE_STRUCTURE(" TERMx%ld: %s\n", (unsigned long int) TrNode_child(current_node), str);
}
/* restore the initial state and continue with sibling nodes */
if (position == TRAVERSE_POSITION_FIRST) {
str_index = current_str_index;
mode = current_mode;
current_node = TrNode_next(current_node);
while (current_node) {
memcpy(arity, current_arity, sizeof(int) * (current_arity[0] + 1));
#ifdef TRIE_COMPACT_PAIRS
if (arity[arity[0]] == -2 && str[str_index - 1] != '[')
str[str_index - 1] = ',';
#else
if (arity[arity[0]] == -1)
str[str_index - 1] = '|';
#endif /* TRIE_COMPACT_PAIRS */
traverse_global_trie(current_node, str, str_index, arity, mode, TRAVERSE_POSITION_NEXT);
current_node = TrNode_next(current_node);
}
free(current_arity);
}
return;
}
static void traverse_global_trie_for_term(gt_node_ptr current_node, char *str, int *str_index, int *arity, int *mode, int type) {
if (TrNode_parent(current_node) != GLOBAL_root_gt)
traverse_global_trie_for_term(TrNode_parent(current_node), str, str_index, arity, mode, type);
traverse_trie_node(TrNode_entry(current_node), str, str_index, arity, mode, type);
return;
}
#endif /* GLOBAL_TRIE */
static void traverse_subgoal_trie(sg_node_ptr current_node, char *str, int str_index, int *arity, int mode, int position) {
int *current_arity = NULL, current_str_index = 0, current_mode = 0;
/* test if hashing */
if (IS_SUBGOAL_TRIE_HASH(current_node)) {
sg_node_ptr *bucket, *last_bucket;
sg_hash_ptr hash;
hash = (sg_hash_ptr) current_node;
bucket = Hash_buckets(hash);
last_bucket = bucket + Hash_num_buckets(hash);
current_arity = (int *) malloc(sizeof(int) * (arity[0] + 1));
memcpy(current_arity, arity, sizeof(int) * (arity[0] + 1));
do {
if (*bucket) {
traverse_subgoal_trie(*bucket, str, str_index, arity, mode, TRAVERSE_POSITION_FIRST);
memcpy(arity, current_arity, sizeof(int) * (current_arity[0] + 1));
#ifdef TRIE_COMPACT_PAIRS
if (arity[arity[0]] == -2 && str[str_index - 1] != '[')
str[str_index - 1] = ',';
#else
if (arity[arity[0]] == -1)
str[str_index - 1] = '|';
#endif /* TRIE_COMPACT_PAIRS */
}
} while (++bucket != last_bucket);
free(current_arity);
return;
}
/* save current state if first sibling node */
if (position == TRAVERSE_POSITION_FIRST) {
current_arity = (int *) malloc(sizeof(int) * (arity[0] + 1));
memcpy(current_arity, arity, sizeof(int) * (arity[0] + 1));
current_str_index = str_index;
current_mode = mode;
}
/* process current trie node */
TrStat_sg_nodes++;
traverse_trie_node(TrNode_entry(current_node), str, &str_index, arity, &mode, TRAVERSE_TYPE_SUBGOAL);
/* continue with child node ... */
if (arity[0] != 0 || mode != TRAVERSE_MODE_NORMAL)
traverse_subgoal_trie(TrNode_child(current_node), str, str_index, arity, mode, TRAVERSE_POSITION_FIRST);
/* ... or show answers */
else {
sg_fr_ptr sg_fr = (sg_fr_ptr) TrNode_sg_fr(current_node);
TrStat_subgoals++;
str[str_index] = 0;
SHOW_TABLE_STRUCTURE("%s.\n", str);
TrStat_ans_nodes++;
if (SgFr_first_answer(sg_fr) == NULL) {
if (SgFr_state(sg_fr) < complete) {
TrStat_sg_incomplete++;
SHOW_TABLE_STRUCTURE(" ---> INCOMPLETE\n");
} else {
TrStat_answers_no++;
SHOW_TABLE_STRUCTURE(" NO\n");
}
} else if (SgFr_first_answer(sg_fr) == SgFr_answer_trie(sg_fr)) {
TrStat_answers_true++;
SHOW_TABLE_STRUCTURE(" TRUE\n");
} else {
arity[0] = 0;
traverse_answer_trie(TrNode_child(SgFr_answer_trie(sg_fr)), &str[str_index], 0, arity, 0, TRAVERSE_MODE_NORMAL, TRAVERSE_POSITION_FIRST);
if (SgFr_state(sg_fr) < complete) {
TrStat_sg_incomplete++;
SHOW_TABLE_STRUCTURE(" ---> INCOMPLETE\n");
}
}
}
/* restore the initial state and continue with sibling nodes */
if (position == TRAVERSE_POSITION_FIRST) {
str_index = current_str_index;
mode = current_mode;
current_node = TrNode_next(current_node);
while (current_node) {
memcpy(arity, current_arity, sizeof(int) * (current_arity[0] + 1));
#ifdef TRIE_COMPACT_PAIRS
if (arity[arity[0]] == -2 && str[str_index - 1] != '[')
str[str_index - 1] = ',';
#else
if (arity[arity[0]] == -1)
str[str_index - 1] = '|';
#endif /* TRIE_COMPACT_PAIRS */
traverse_subgoal_trie(current_node, str, str_index, arity, mode, TRAVERSE_POSITION_NEXT);
current_node = TrNode_next(current_node);
}
free(current_arity);
}
return;
}
static void traverse_answer_trie(ans_node_ptr current_node, char *str, int str_index, int *arity, int var_index, int mode, int position) {
int *current_arity = NULL, current_str_index = 0, current_var_index = 0, current_mode = 0;
/* test if hashing */
if (IS_ANSWER_TRIE_HASH(current_node)) {
ans_node_ptr *bucket, *last_bucket;
ans_hash_ptr hash;
hash = (ans_hash_ptr) current_node;
bucket = Hash_buckets(hash);
last_bucket = bucket + Hash_num_buckets(hash);
current_arity = (int *) malloc(sizeof(int) * (arity[0] + 1));
memcpy(current_arity, arity, sizeof(int) * (arity[0] + 1));
do {
if (*bucket) {
traverse_answer_trie(*bucket, str, str_index, arity, var_index, mode, TRAVERSE_POSITION_FIRST);
memcpy(arity, current_arity, sizeof(int) * (current_arity[0] + 1));
#ifdef TRIE_COMPACT_PAIRS
if (arity[arity[0]] == -2 && str[str_index - 1] != '[')
str[str_index - 1] = ',';
#else
if (arity[arity[0]] == -1)
str[str_index - 1] = '|';
#endif /* TRIE_COMPACT_PAIRS */
}
} while (++bucket != last_bucket);
free(current_arity);
return;
}
/* save current state if first sibling node */
if (position == TRAVERSE_POSITION_FIRST) {
current_arity = (int *) malloc(sizeof(int) * (arity[0] + 1));
memcpy(current_arity, arity, sizeof(int) * (arity[0] + 1));
current_str_index = str_index;
current_var_index = var_index;
current_mode = mode;
}
/* print VAR if starting a term */
if (arity[0] == 0 && mode == TRAVERSE_MODE_NORMAL) {
str_index += sprintf(& str[str_index], " VAR%d: ", var_index);
var_index++;
}
/* process current trie node */
TrStat_ans_nodes++;
traverse_trie_node(TrNode_entry(current_node), str, &str_index, arity, &mode, TRAVERSE_TYPE_ANSWER);
/* show answer .... */
if (IS_ANSWER_LEAF_NODE(current_node)) {
TrStat_answers++;
str[str_index] = 0;
SHOW_TABLE_STRUCTURE("%s\n", str);
}
#ifdef TABLING_INNER_CUTS
/* ... or continue with pruned node */
else if (TrNode_child(current_node) == NULL) {
TrStat_answers++;
TrStat_answers_pruned++;
}
#endif /* TABLING_INNER_CUTS */
/* ... or continue with child node */
else
traverse_answer_trie(TrNode_child(current_node), str, str_index, arity, var_index, mode, TRAVERSE_POSITION_FIRST);
/* restore the initial state and continue with sibling nodes */
if (position == TRAVERSE_POSITION_FIRST) {
str_index = current_str_index;
var_index = current_var_index;
mode = current_mode;
current_node = TrNode_next(current_node);
while (current_node) {
memcpy(arity, current_arity, sizeof(int) * (current_arity[0] + 1));
#ifdef TRIE_COMPACT_PAIRS
if (arity[arity[0]] == -2 && str[str_index - 1] != '[')
str[str_index - 1] = ',';
#else
if (arity[arity[0]] == -1)
str[str_index - 1] = '|';
#endif /* TRIE_COMPACT_PAIRS */
traverse_answer_trie(current_node, str, str_index, arity, var_index, mode, TRAVERSE_POSITION_NEXT);
current_node = TrNode_next(current_node);
}
free(current_arity);
}
return;
}
static inline void traverse_trie_node(Term t, char *str, int *str_index_ptr, int *arity, int *mode_ptr, int type) {
int mode = *mode_ptr;
int str_index = *str_index_ptr;
/* test the node type */
if (mode == TRAVERSE_MODE_DOUBLE) {
#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P
arity[0]++;
arity[arity[0]] = (int) t;
mode = TRAVERSE_MODE_DOUBLE2;
} else if (mode == TRAVERSE_MODE_DOUBLE2) {
volatile Float dbl;
volatile Term *t_dbl = (Term *)((void *) &dbl);
t_dbl[0] = t;
t_dbl[1] = (Term) arity[arity[0]];
arity[0]--;
#else /* SIZEOF_DOUBLE == SIZEOF_INT_P */
volatile Float dbl;
volatile Term *t_dbl = (Term *)((void *) &dbl);
t_dbl[0] = t;
#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */
str_index += sprintf(& str[str_index], "%.15g", dbl);
while (arity[0]) {
if (arity[arity[0]] > 0) {
arity[arity[0]]--;
if (arity[arity[0]] == 0) {
str_index += sprintf(& str[str_index], ")");
arity[0]--;
} else {
str_index += sprintf(& str[str_index], ",");
break;
}
} else {
if (arity[arity[0]] == -2) {
#ifdef TRIE_COMPACT_PAIRS
str_index += sprintf(& str[str_index], ",");
#else
str_index += sprintf(& str[str_index], "|");
arity[arity[0]] = -1;
#endif /* TRIE_COMPACT_PAIRS */
break;
} else {
str_index += sprintf(& str[str_index], "]");
arity[0]--;
}
}
}
#ifndef GLOBAL_TRIE
if (type == TRAVERSE_TYPE_SUBGOAL)
mode = TRAVERSE_MODE_NORMAL;
else /* type == TRAVERSE_TYPE_ANSWER */
#endif /* GLOBAL_TRIE */
mode = TRAVERSE_MODE_DOUBLE_END;
} else if (mode == TRAVERSE_MODE_DOUBLE_END) {
mode = TRAVERSE_MODE_NORMAL;
} else if (mode == TRAVERSE_MODE_LONGINT) {
Int li = (Int) t;
#if SHORT_INTS
str_index += sprintf(& str[str_index], "%ld", li);
#else
str_index += sprintf(& str[str_index], "%d", li);
#endif /* SHORT_INTS */
while (arity[0]) {
if (arity[arity[0]] > 0) {
arity[arity[0]]--;
if (arity[arity[0]] == 0) {
str_index += sprintf(& str[str_index], ")");
arity[0]--;
} else {
str_index += sprintf(& str[str_index], ",");
break;
}
} else {
if (arity[arity[0]] == -2) {
#ifdef TRIE_COMPACT_PAIRS
str_index += sprintf(& str[str_index], ",");
#else
str_index += sprintf(& str[str_index], "|");
arity[arity[0]] = -1;
#endif /* TRIE_COMPACT_PAIRS */
break;
} else {
str_index += sprintf(& str[str_index], "]");
arity[0]--;
}
}
}
#ifndef GLOBAL_TRIE
if (type == TRAVERSE_TYPE_SUBGOAL)
mode = TRAVERSE_MODE_NORMAL;
else /* type == TRAVERSE_TYPE_ANSWER */
#endif /* GLOBAL_TRIE */
mode = TRAVERSE_MODE_LONGINT_END;
} else if (mode == TRAVERSE_MODE_LONGINT_END) {
mode = TRAVERSE_MODE_NORMAL;
} else if (IsVarTerm(t)) {
#ifdef GLOBAL_TRIE
if (t > VarIndexOfTableTerm(MAX_TABLE_VARS)) {
TrStat_gt_refs++;
traverse_global_trie_for_term((gt_node_ptr) t, str, &str_index, arity, &mode, type);
} else
#endif /* GLOBAL_TRIE */
{
if (type == TRAVERSE_TYPE_SUBGOAL)
str_index += sprintf(& str[str_index], "VAR%d", VarIndexOfTableTerm(t));
else /* type == TRAVERSE_TYPE_ANSWER */
str_index += sprintf(& str[str_index], "ANSVAR%d", VarIndexOfTableTerm(t));
while (arity[0]) {
if (arity[arity[0]] > 0) {
arity[arity[0]]--;
if (arity[arity[0]] == 0) {
str_index += sprintf(& str[str_index], ")");
arity[0]--;
} else {
str_index += sprintf(& str[str_index], ",");
break;
}
} else {
if (arity[arity[0]] == -2) {
#ifdef TRIE_COMPACT_PAIRS
str_index += sprintf(& str[str_index], ",");
#else
str_index += sprintf(& str[str_index], "|");
arity[arity[0]] = -1;
#endif /* TRIE_COMPACT_PAIRS */
break;
} else {
str_index += sprintf(& str[str_index], "]");
arity[0]--;
}
}
}
}
} else if (IsIntTerm(t)) {
#if SHORT_INTS
str_index += sprintf(& str[str_index], "%ld", IntOfTerm(t));
#else
str_index += sprintf(& str[str_index], "%d", IntOfTerm(t));
#endif /* SHORT_INTS */
while (arity[0]) {
if (arity[arity[0]] > 0) {
arity[arity[0]]--;
if (arity[arity[0]] == 0) {
str_index += sprintf(& str[str_index], ")");
arity[0]--;
} else {
str_index += sprintf(& str[str_index], ",");
break;
}
} else {
if (arity[arity[0]] == -2) {
#ifdef TRIE_COMPACT_PAIRS
str_index += sprintf(& str[str_index], ",");
#else
str_index += sprintf(& str[str_index], "|");
arity[arity[0]] = -1;
#endif /* TRIE_COMPACT_PAIRS */
break;
} else {
str_index += sprintf(& str[str_index], "]");
arity[0]--;
}
}
}
} else if (IsAtomTerm(t)) {
#ifndef TRIE_COMPACT_PAIRS
if (arity[arity[0]] == -1 && t == TermNil) {
str[str_index - 1] = ']';
arity[0]--;
} else
#endif /* TRIE_COMPACT_PAIRS */
str_index += sprintf(& str[str_index], "%s", AtomName(AtomOfTerm(t)));
while (arity[0]) {
if (arity[arity[0]] > 0) {
arity[arity[0]]--;
if (arity[arity[0]] == 0) {
str_index += sprintf(& str[str_index], ")");
arity[0]--;
} else {
str_index += sprintf(& str[str_index], ",");
break;
}
} else {
if (arity[arity[0]] == -2) {
#ifdef TRIE_COMPACT_PAIRS
str_index += sprintf(& str[str_index], ",");
#else
str_index += sprintf(& str[str_index], "|");
arity[arity[0]] = -1;
#endif /* TRIE_COMPACT_PAIRS */
break;
} else {
str_index += sprintf(& str[str_index], "]");
arity[0]--;
}
}
}
} else if (IsPairTerm(t)) {
#ifdef TRIE_COMPACT_PAIRS
if (t == CompactPairEndList)
arity[arity[0]] = -1;
else if (t == CompactPairEndTerm) {
str[str_index - 1] = '|';
arity[arity[0]] = -1;
#else
if (arity[arity[0]] == -1) {
str[str_index - 1] = ',';
arity[arity[0]] = -2;
#endif /* TRIE_COMPACT_PAIRS */
} else {
str_index += sprintf(& str[str_index], "[");
arity[0]++;
arity[arity[0]] = -2;
}
} else if (IsApplTerm(t)) {
Functor f = (Functor) RepAppl(t);
if (f == FunctorDouble) {
mode = TRAVERSE_MODE_DOUBLE;
} else if (f == FunctorLongInt) {
mode = TRAVERSE_MODE_LONGINT;
} else {
str_index += sprintf(& str[str_index], "%s(", AtomName(NameOfFunctor(f)));
arity[0]++;
arity[arity[0]] = ArityOfFunctor(f);
}
}
*mode_ptr = mode;
*str_index_ptr = str_index;
return;
}
#ifdef YAPOR
#ifdef TABLING_INNER_CUTS
static int update_answer_trie_branch(ans_node_ptr previous_node, ans_node_ptr current_node) {
int ltt;
if (! IS_ANSWER_LEAF_NODE(current_node)) {
if (TrNode_child(current_node)) {
TrNode_instr(TrNode_child(current_node)) -= 1; /* retry --> try */
update_answer_trie_branch(NULL, TrNode_child(current_node));
if (TrNode_child(current_node))
goto update_next_trie_branch;
}
/* node belonging to a pruned answer */
if (previous_node) {
TrNode_next(previous_node) = TrNode_next(current_node);
FREE_ANSWER_TRIE_NODE(current_node);
if (TrNode_next(previous_node)) {
return update_answer_trie_branch(previous_node, TrNode_next(previous_node));
} else {
TrNode_instr(previous_node) -= 2; /* retry --> trust : try --> do */
return 0;
}
} else {
TrNode_child(TrNode_parent(current_node)) = TrNode_next(current_node);
if (TrNode_next(current_node)) {
TrNode_instr(TrNode_next(current_node)) -= 1; /* retry --> try */
update_answer_trie_branch(NULL, TrNode_next(current_node));
}
FREE_ANSWER_TRIE_NODE(current_node);
return 0;
}
}
update_next_trie_branch:
if (TrNode_next(current_node)) {
ltt = 1 + update_answer_trie_branch(current_node, TrNode_next(current_node));
} else {
TrNode_instr(current_node) -= 2; /* retry --> trust : try --> do */
ltt = 1;
}
TrNode_or_arg(current_node) = ltt;
TrNode_instr(current_node) = Yap_opcode(TrNode_instr(current_node));
return ltt;
}
#else /* YAPOR && ! TABLING_INNER_CUTS */
static int update_answer_trie_branch(ans_node_ptr current_node) {
int ltt;
if (! IS_ANSWER_LEAF_NODE(current_node)) {
TrNode_instr(TrNode_child(current_node)) -= 1; /* retry --> try */
update_answer_trie_branch(TrNode_child(current_node));
}
if (TrNode_next(current_node)) {
ltt = 1 + update_answer_trie_branch(TrNode_next(current_node));
} else {
TrNode_instr(current_node) -= 2; /* retry --> trust : try --> do */
ltt = 1;
}
TrNode_or_arg(current_node) = ltt;
TrNode_instr(current_node) = Yap_opcode(TrNode_instr(current_node));
return ltt;
}
#endif
#else /* ! YAPOR */
static void update_answer_trie_branch(ans_node_ptr current_node, int position) {
if (! IS_ANSWER_LEAF_NODE(current_node))
update_answer_trie_branch(TrNode_child(current_node), TRAVERSE_POSITION_FIRST); /* retry --> try */
if (position == TRAVERSE_POSITION_FIRST) {
ans_node_ptr next = TrNode_next(current_node);
if (next) {
while (TrNode_next(next)) {
update_answer_trie_branch(next, TRAVERSE_POSITION_NEXT); /* retry --> retry */
next = TrNode_next(next);
}
update_answer_trie_branch(next, TRAVERSE_POSITION_LAST); /* retry --> trust */
} else
position += TRAVERSE_POSITION_LAST; /* try --> do */
}
TrNode_instr(current_node) = Yap_opcode(TrNode_instr(current_node) - position);
return;
}
#endif /* YAPOR */
/*******************************
** Global functions **
*******************************/
sg_fr_ptr subgoal_search(yamop *preg, CELL **Yaddr) {
CELL *stack_vars;
int i, subs_arity, pred_arity;
tab_ent_ptr tab_ent;
sg_fr_ptr sg_fr;
sg_node_ptr current_sg_node;
stack_vars = *Yaddr;
subs_arity = 0;
pred_arity = preg->u.Otapl.s;
tab_ent = preg->u.Otapl.te;
current_sg_node = TabEnt_subgoal_trie(tab_ent);
#ifdef TABLE_LOCK_AT_ENTRY_LEVEL
LOCK(TabEnt_lock(tab_ent));
#endif /* TABLE_LOCK_LEVEL */
for (i = 1; i <= pred_arity; i++) {
current_sg_node = subgoal_search_loop(tab_ent, current_sg_node, Deref(XREGS[i]), &subs_arity, &stack_vars);
}
STACK_PUSH_UP(subs_arity, stack_vars);
*Yaddr = stack_vars++;
/* reset variables */
while (subs_arity--) {
Term t = STACK_POP_DOWN(stack_vars);
RESET_VARIABLE(t);
}
#if defined(TABLE_LOCK_AT_NODE_LEVEL)
LOCK(TrNode_lock(current_sg_node));
#elif defined(TABLE_LOCK_AT_WRITE_LEVEL)
LOCK_TABLE(current_sg_node);
#endif /* TABLE_LOCK_LEVEL */
if (TrNode_sg_fr(current_sg_node) == NULL) {
/* new tabled subgoal */
new_subgoal_frame(sg_fr, preg);
TrNode_sg_fr(current_sg_node) = (sg_node_ptr) sg_fr;
} else {
sg_fr = (sg_fr_ptr) TrNode_sg_fr(current_sg_node);
#ifdef LIMIT_TABLING
if (SgFr_state(sg_fr) <= ready) { /* incomplete or ready */
remove_from_global_sg_fr_list(sg_fr);
}
#endif /* LIMIT_TABLING */
}
#if defined(TABLE_LOCK_AT_ENTRY_LEVEL)
UNLOCK(TabEnt_lock(tab_ent));
#elif defined(TABLE_LOCK_AT_NODE_LEVEL)
UNLOCK(TrNode_lock(current_sg_node));
#elif defined(TABLE_LOCK_AT_WRITE_LEVEL)
UNLOCK_TABLE(current_sg_node);
#endif /* TABLE_LOCK_LEVEL */
return sg_fr;
}
ans_node_ptr answer_search(sg_fr_ptr sg_fr, CELL *subs_ptr) {
#define subs_arity *subs_ptr
CELL *stack_vars;
int i, vars_arity;
ans_node_ptr current_ans_node;
vars_arity = 0;
current_ans_node = SgFr_answer_trie(sg_fr);
for (i = subs_arity; i >= 1; i--) {
#ifdef TABLING_ERRORS
if (IsNonVarTerm(subs_ptr[i]))
TABLING_ERROR_MESSAGE("IsNonVarTem(subs_ptr[i]) (answer_search)");
#endif /* TABLING_ERRORS */
current_ans_node = answer_search_loop(sg_fr, current_ans_node, Deref(subs_ptr[i]), &vars_arity);
}
/* reset variables */
stack_vars = (CELL *) TR;
while (vars_arity--) {
Term t = STACK_POP_DOWN(stack_vars);
RESET_VARIABLE(t);
}
return current_ans_node;
#undef subs_arity
}
void load_answer(ans_node_ptr current_ans_node, CELL *subs_ptr) {
#define subs_arity *subs_ptr
CELL *stack_terms;
int i;
#ifdef TABLING_ERRORS
if (H < H_FZ)
TABLING_ERROR_MESSAGE("H < H_FZ (load_answer)");
#endif /* TABLING_ERRORS */
if (subs_arity == 0)
return;
stack_terms = load_answer_loop(current_ans_node);
for (i = subs_arity; i >= 1; i--) {
Term t = STACK_POP_DOWN(stack_terms);
Bind((CELL *) subs_ptr[i], t);
}
#ifdef TABLING_ERRORS
if (stack_terms != (CELL *)Yap_TrailTop)
TABLING_ERROR_MESSAGE("stack_terms != Yap_TrailTop (load_answer)");
#endif /* TABLING_ERRORS */
return;
#undef subs_arity
}
#ifdef GLOBAL_TRIE
CELL *exec_substitution(gt_node_ptr current_node, CELL *aux_stack) {
#define subs_arity *subs_ptr
CELL *stack_terms, *subs_ptr;
Term t;
++aux_stack; /* skip the heap_arity entry */
stack_terms = exec_substitution_loop(current_node, &aux_stack, (CELL *) Yap_TrailTop);
*--aux_stack = 0; /* restore the heap_arity entry */
subs_ptr = aux_stack + aux_stack[1] + 2;
t = STACK_POP_DOWN(stack_terms);
Bind((CELL *) subs_ptr[subs_arity], t);
#ifdef TABLING_ERRORS
if (stack_terms != (CELL *)Yap_TrailTop)
TABLING_ERROR_MESSAGE("stack_terms != Yap_TrailTop (exec_substitution)");
#endif /* TABLING_ERRORS */
*subs_ptr = subs_arity - 1;
return aux_stack;
#undef subs_arity
}
#endif /* GLOBAL_TRIE */
#ifdef GLOBAL_TRIE
void free_subgoal_trie_branch(sg_node_ptr current_node, int nodes_left, int position) {
if (nodes_left) {
free_subgoal_trie_branch(TrNode_child(current_node), nodes_left - 1, TRAVERSE_POSITION_FIRST);
#else
void free_subgoal_trie_branch(sg_node_ptr current_node, int nodes_left, int nodes_extra, int position) {
if (nodes_left) {
int current_nodes_left = 0, current_nodes_extra = 0;
/* save current state if first sibling node */
if (position == TRAVERSE_POSITION_FIRST) {
current_nodes_left = nodes_left;
current_nodes_extra = nodes_extra;
}
if (nodes_extra) {
#ifdef TRIE_COMPACT_PAIRS
if (nodes_extra < 0) {
Term t = TrNode_entry(current_node);
if (IsPairTerm(t)) {
if (t == CompactPairInit)
nodes_extra--;
else /* CompactPairEndList / CompactPairEndTerm */
nodes_extra++;
}
} else
#endif /* TRIE_COMPACT_PAIRS */
if (--nodes_extra == 0)
nodes_left--;
} else {
Term t = TrNode_entry(current_node);
if (IsVarTerm(t) || IsAtomOrIntTerm(t))
nodes_left--;
else if (IsPairTerm(t))
#ifdef TRIE_COMPACT_PAIRS
/* CompactPairInit */
nodes_extra = -1;
#else
nodes_left++;
#endif /* TRIE_COMPACT_PAIRS */
else if (IsApplTerm(t)) {
Functor f = (Functor) RepAppl(t);
if (f == FunctorDouble)
#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P
nodes_extra = 2;
#else
nodes_extra = 1;
#endif /* SIZEOF_DOUBLE x SIZEOF_INT_P */
else if (f == FunctorLongInt)
nodes_extra = 1;
else
nodes_left += ArityOfFunctor(f) - 1;
}
}
free_subgoal_trie_branch(TrNode_child(current_node), nodes_left, nodes_extra, TRAVERSE_POSITION_FIRST);
#endif /* GLOBAL_TRIE */
if (position == TRAVERSE_POSITION_FIRST) {
sg_node_ptr next_node = TrNode_next(current_node);
DECREMENT_GLOBAL_TRIE_REFERENCE(TrNode_entry(current_node));
FREE_SUBGOAL_TRIE_NODE(current_node);
#ifndef GLOBAL_TRIE
/* restore the initial state */
nodes_left = current_nodes_left;
nodes_extra = current_nodes_extra;
#endif /* GLOBAL_TRIE */
while (next_node) {
current_node = next_node;
next_node = TrNode_next(current_node);
#ifdef GLOBAL_TRIE
free_subgoal_trie_branch(current_node, nodes_left, TRAVERSE_POSITION_NEXT);
#else
free_subgoal_trie_branch(current_node, nodes_left, nodes_extra, TRAVERSE_POSITION_NEXT);
#endif /* GLOBAL_TRIE */
}
} else {
DECREMENT_GLOBAL_TRIE_REFERENCE(TrNode_entry(current_node));
FREE_SUBGOAL_TRIE_NODE(current_node);
}
} else {
sg_fr_ptr sg_fr;
ans_node_ptr ans_node;
sg_fr = (sg_fr_ptr) current_node;
free_answer_trie_hash_chain(SgFr_hash_chain(sg_fr));
ans_node = SgFr_answer_trie(sg_fr);
if (TrNode_child(ans_node))
free_answer_trie_branch(TrNode_child(ans_node), TRAVERSE_POSITION_FIRST);
FREE_ANSWER_TRIE_NODE(ans_node);
#ifdef LIMIT_TABLING
remove_from_global_sg_fr_list(sg_fr);
#endif /* LIMIT_TABLING */
FREE_SUBGOAL_FRAME(sg_fr);
}
return;
}
void free_answer_trie_branch(ans_node_ptr current_node, int position) {
#ifdef TABLING_INNER_CUTS
if (! IS_ANSWER_LEAF_NODE(current_node) && TrNode_child(current_node))
#else
if (! IS_ANSWER_LEAF_NODE(current_node))
#endif /* TABLING_INNER_CUTS */
free_answer_trie_branch(TrNode_child(current_node), TRAVERSE_POSITION_FIRST);
if (position == TRAVERSE_POSITION_FIRST) {
ans_node_ptr next_node = TrNode_next(current_node);
DECREMENT_GLOBAL_TRIE_REFERENCE(TrNode_entry(current_node));
FREE_ANSWER_TRIE_NODE(current_node);
while (next_node) {
current_node = next_node;
next_node = TrNode_next(current_node);
free_answer_trie_branch(current_node, TRAVERSE_POSITION_NEXT);
}
} else {
DECREMENT_GLOBAL_TRIE_REFERENCE(TrNode_entry(current_node));
FREE_ANSWER_TRIE_NODE(current_node);
}
return;
}
void update_answer_trie(sg_fr_ptr sg_fr) {
ans_node_ptr current_node;
free_answer_trie_hash_chain(SgFr_hash_chain(sg_fr));
SgFr_hash_chain(sg_fr) = NULL;
SgFr_state(sg_fr) += 2; /* complete --> compiled : complete_in_use --> compiled_in_use */
current_node = TrNode_child(SgFr_answer_trie(sg_fr));
if (current_node) {
#ifdef YAPOR
TrNode_instr(current_node) -= 1;
#ifdef TABLING_INNER_CUTS
update_answer_trie_branch(NULL, current_node);
#else
update_answer_trie_branch(current_node);
#endif /* TABLING_INNER_CUTS */
#else /* TABLING */
update_answer_trie_branch(current_node, TRAVERSE_POSITION_FIRST);
#endif /* YAPOR */
}
return;
}
void show_table(tab_ent_ptr tab_ent, int show_mode) {
sg_node_ptr sg_node;
TrStat_show = show_mode;
if (show_mode == SHOW_MODE_STATISTICS) {
TrStat_subgoals = 0;
TrStat_sg_incomplete = 0;
TrStat_sg_nodes = 1;
TrStat_answers = 0;
TrStat_answers_true = 0;
TrStat_answers_no = 0;
#ifdef TABLING_INNER_CUTS
TrStat_answers_pruned = 0;
#endif /* TABLING_INNER_CUTS */
TrStat_ans_nodes = 0;
#ifdef GLOBAL_TRIE
TrStat_gt_refs = 0;
#endif /* GLOBAL_TRIE */
fprintf(Yap_stdout, "Table statistics for predicate '%s/%d'\n", AtomName(TabEnt_atom(tab_ent)), TabEnt_arity(tab_ent));
} else { /* SHOW_MODE_STRUCTURE */
fprintf(Yap_stdout, "Table structure for predicate '%s/%d'\n", AtomName(TabEnt_atom(tab_ent)), TabEnt_arity(tab_ent));
}
sg_node = TrNode_child(TabEnt_subgoal_trie(tab_ent));
if (sg_node) {
if (TabEnt_arity(tab_ent)) {
char *str = (char *) malloc(sizeof(char) * SHOW_TABLE_STR_ARRAY_SIZE);
int str_index = sprintf(str, " ?- %s(", AtomName(TabEnt_atom(tab_ent)));
int *arity = (int *) malloc(sizeof(int) * SHOW_TABLE_ARITY_ARRAY_SIZE);
arity[0] = 1;
arity[1] = TabEnt_arity(tab_ent);
traverse_subgoal_trie(sg_node, str, str_index, arity, TRAVERSE_MODE_NORMAL, TRAVERSE_POSITION_FIRST);
free(str);
free(arity);
} else {
sg_fr_ptr sg_fr = (sg_fr_ptr) sg_node;
TrStat_subgoals++;
SHOW_TABLE_STRUCTURE(" ?- %s.\n", AtomName(TabEnt_atom(tab_ent)));
TrStat_ans_nodes++;
if (SgFr_first_answer(sg_fr) == NULL) {
if (SgFr_state(sg_fr) < complete) {
TrStat_sg_incomplete++;
SHOW_TABLE_STRUCTURE(" ---> INCOMPLETE\n");
} else {
TrStat_answers_no++;
SHOW_TABLE_STRUCTURE(" NO\n");
}
} else { /* SgFr_first_answer(sg_fr) == SgFr_answer_trie(sg_fr) */
TrStat_answers_true++;
SHOW_TABLE_STRUCTURE(" TRUE\n");
}
}
} else
SHOW_TABLE_STRUCTURE(" EMPTY\n");
if (show_mode == SHOW_MODE_STATISTICS) {
fprintf(Yap_stdout, " Subgoal trie structure\n");
fprintf(Yap_stdout, " Subgoals: %ld (%ld incomplete)\n", TrStat_subgoals, TrStat_sg_incomplete);
fprintf(Yap_stdout, " Subgoal trie nodes: %ld\n", TrStat_sg_nodes);
fprintf(Yap_stdout, " Answer trie structure(s)\n");
#ifdef TABLING_INNER_CUTS
fprintf(Yap_stdout, " Answers: %ld (%ld pruned)\n", TrStat_answers, TrStat_answers_pruned);
#else
fprintf(Yap_stdout, " Answers: %ld\n", TrStat_answers);
#endif /* TABLING_INNER_CUTS */
fprintf(Yap_stdout, " Answers 'TRUE': %ld\n", TrStat_answers_true);
fprintf(Yap_stdout, " Answers 'NO': %ld\n", TrStat_answers_no);
fprintf(Yap_stdout, " Answer trie nodes: %ld\n", TrStat_ans_nodes);
#ifdef GLOBAL_TRIE
fprintf(Yap_stdout, " Global trie references: %ld\n", TrStat_gt_refs);
#endif /* GLOBAL_TRIE */
}
return;
}
#ifdef GLOBAL_TRIE
void show_global_trie(int show_mode) {
TrStat_show = show_mode;
if (show_mode == SHOW_MODE_STATISTICS) {
TrStat_gt_terms = 0;
TrStat_gt_nodes = 1;
TrStat_gt_refs = 0;
fprintf(Yap_stdout, "Global trie statistics\n");
} else { /* SHOW_MODE_STRUCTURE */
fprintf(Yap_stdout, "Global trie structure\n");
}
if (TrNode_child(GLOBAL_root_gt)) {
char *str = (char *) malloc(sizeof(char) * SHOW_TABLE_STR_ARRAY_SIZE);
int *arity = (int *) malloc(sizeof(int) * SHOW_TABLE_ARITY_ARRAY_SIZE);
arity[0] = 0;
traverse_global_trie(TrNode_child(GLOBAL_root_gt), str, 0, arity, TRAVERSE_MODE_NORMAL, TRAVERSE_POSITION_FIRST);
free(str);
free(arity);
} else
SHOW_TABLE_STRUCTURE(" EMPTY\n");
if (show_mode == SHOW_MODE_STATISTICS) {
fprintf(Yap_stdout, " Terms: %ld\n", TrStat_gt_terms);
fprintf(Yap_stdout, " Global trie nodes: %ld\n", TrStat_gt_nodes);
fprintf(Yap_stdout, " Global trie auto references: %ld\n", TrStat_gt_refs);
}
return;
}
#endif /* GLOBAL_TRIE */
void private_completion(sg_fr_ptr sg_fr) {
/* complete subgoals */
#ifdef LIMIT_TABLING
sg_fr_ptr aux_sg_fr;
while (LOCAL_top_sg_fr != sg_fr) {
aux_sg_fr = LOCAL_top_sg_fr;
LOCAL_top_sg_fr = SgFr_next(aux_sg_fr);
mark_as_completed(aux_sg_fr);
insert_into_global_sg_fr_list(aux_sg_fr);
}
aux_sg_fr = LOCAL_top_sg_fr;
LOCAL_top_sg_fr = SgFr_next(aux_sg_fr);
mark_as_completed(aux_sg_fr);
insert_into_global_sg_fr_list(aux_sg_fr);
#else
while (LOCAL_top_sg_fr != sg_fr) {
mark_as_completed(LOCAL_top_sg_fr);
LOCAL_top_sg_fr = SgFr_next(LOCAL_top_sg_fr);
}
mark_as_completed(LOCAL_top_sg_fr);
LOCAL_top_sg_fr = SgFr_next(LOCAL_top_sg_fr);
#endif /* LIMIT_TABLING */
/* release dependency frames */
while (EQUAL_OR_YOUNGER_CP(DepFr_cons_cp(LOCAL_top_dep_fr), B)) { /* never equal if batched scheduling */
dep_fr_ptr dep_fr = DepFr_next(LOCAL_top_dep_fr);
FREE_DEPENDENCY_FRAME(LOCAL_top_dep_fr);
LOCAL_top_dep_fr = dep_fr;
}
/* adjust freeze registers */
adjust_freeze_registers();
return;
}
#endif /* TABLING */