in the local tries (and not in the global trie). This required major changes to the trie instructions in order to unify the use of the auxiliary stack organization for the terms in the local tries and in the global trie.
1131 lines
44 KiB
C
1131 lines
44 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 <stdlib.h>
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
#include "opt.mavar.h"
|
|
|
|
static inline CELL *expand_auxiliary_stack(CELL *);
|
|
static inline void adjust_freeze_registers(void);
|
|
static inline void mark_as_completed(sg_fr_ptr);
|
|
static inline void unbind_variables(tr_fr_ptr, tr_fr_ptr);
|
|
static inline void rebind_variables(tr_fr_ptr, tr_fr_ptr);
|
|
static inline void restore_bindings(tr_fr_ptr, tr_fr_ptr);
|
|
static inline void abolish_incomplete_subgoals(choiceptr);
|
|
static inline void free_subgoal_trie_hash_chain(sg_hash_ptr);
|
|
static inline void free_answer_trie_hash_chain(ans_hash_ptr);
|
|
static inline choiceptr freeze_current_cp(void);
|
|
static inline void resume_frozen_cp(choiceptr);
|
|
static inline void abolish_all_frozen_cps(void);
|
|
#ifdef YAPOR
|
|
static inline void pruning_over_tabling_data_structures(void);
|
|
static inline void collect_suspension_frames(or_fr_ptr);
|
|
#ifdef TIMESTAMP_CHECK
|
|
static inline susp_fr_ptr suspension_frame_to_resume(or_fr_ptr, long);
|
|
#else
|
|
static inline susp_fr_ptr suspension_frame_to_resume(or_fr_ptr);
|
|
#endif /* TIMESTAMP_CHECK */
|
|
#endif /* YAPOR */
|
|
#ifdef TABLING_INNER_CUTS
|
|
static inline void CUT_store_tg_answer(or_fr_ptr, ans_node_ptr, choiceptr, int);
|
|
static inline tg_sol_fr_ptr CUT_store_tg_answers(or_fr_ptr, tg_sol_fr_ptr, int);
|
|
static inline void CUT_validate_tg_answers(tg_sol_fr_ptr);
|
|
static inline void CUT_join_tg_solutions(tg_sol_fr_ptr *, tg_sol_fr_ptr);
|
|
static inline void CUT_join_solution_frame_tg_answers(tg_sol_fr_ptr);
|
|
static inline void CUT_join_solution_frames_tg_answers(tg_sol_fr_ptr);
|
|
static inline void CUT_free_tg_solution_frame(tg_sol_fr_ptr);
|
|
static inline void CUT_free_tg_solution_frames(tg_sol_fr_ptr);
|
|
static inline tg_sol_fr_ptr CUT_prune_tg_solution_frames(tg_sol_fr_ptr, int);
|
|
#endif /* TABLING_INNER_CUTS */
|
|
|
|
|
|
|
|
/*********************
|
|
** Macros **
|
|
*********************/
|
|
|
|
#define SHOW_MODE_STRUCTURE 0
|
|
#define SHOW_MODE_STATISTICS 1
|
|
#define TRAVERSE_TYPE_SUBGOAL 0
|
|
#define TRAVERSE_TYPE_ANSWER 1
|
|
#define TRAVERSE_MODE_NORMAL 0
|
|
#define TRAVERSE_MODE_DOUBLE 1
|
|
#define TRAVERSE_MODE_DOUBLE2 2
|
|
#define TRAVERSE_MODE_DOUBLE_END 3
|
|
#define TRAVERSE_MODE_LONGINT 4
|
|
#define TRAVERSE_MODE_LONGINT_END 5
|
|
/* do not change order !!! */
|
|
#define TRAVERSE_POSITION_NEXT 0
|
|
#define TRAVERSE_POSITION_FIRST 1
|
|
#define TRAVERSE_POSITION_LAST 2
|
|
|
|
/* LowTagBits is 3 for 32 bit-machines and 7 for 64 bit-machines */
|
|
#define NumberOfLowTagBits (LowTagBits == 3 ? 2 : 3)
|
|
#define MakeTableVarTerm(INDEX) ((INDEX) << NumberOfLowTagBits)
|
|
#define VarIndexOfTableTerm(TERM) (((unsigned int) (TERM)) >> NumberOfLowTagBits)
|
|
#define VarIndexOfTerm(TERM) \
|
|
((((CELL) (TERM)) - GLOBAL_table_var_enumerator(0)) / sizeof(CELL))
|
|
#define IsTableVarTerm(TERM) \
|
|
((CELL) (TERM)) >= GLOBAL_table_var_enumerator(0) && \
|
|
((CELL) (TERM)) <= GLOBAL_table_var_enumerator(MAX_TABLE_VARS - 1)
|
|
#ifdef TRIE_COMPACT_PAIRS
|
|
#define PairTermMark NULL
|
|
#define CompactPairInit AbsPair((Term *) 0)
|
|
#define CompactPairEndTerm AbsPair((Term *) (LowTagBits + 1))
|
|
#define CompactPairEndList AbsPair((Term *) (2*(LowTagBits + 1)))
|
|
#endif /* TRIE_COMPACT_PAIRS */
|
|
|
|
#define NORM_CP(CP) ((choiceptr)(CP))
|
|
#define GEN_CP(CP) ((struct generator_choicept *)(CP))
|
|
#define CONS_CP(CP) ((struct consumer_choicept *)(CP))
|
|
#define LOAD_CP(CP) ((struct loader_choicept *)(CP))
|
|
#ifdef DETERMINISTIC_TABLING
|
|
#define DET_GEN_CP(CP) ((struct deterministic_generator_choicept *)(CP))
|
|
#define IS_DET_GEN_CP(CP) (*(CELL*)(DET_GEN_CP(CP) + 1) <= MAX_TABLE_VARS)
|
|
#define IS_BATCHED_NORM_GEN_CP(CP) (GEN_CP(CP)->cp_dep_fr == NULL)
|
|
#define IS_BATCHED_GEN_CP(CP) (IS_DET_GEN_CP(CP) || IS_BATCHED_NORM_GEN_CP(CP))
|
|
#else
|
|
#define IS_BATCHED_GEN_CP(CP) (GEN_CP(CP)->cp_dep_fr == NULL)
|
|
#endif /* DETERMINISTIC_TABLING */
|
|
|
|
#define TAG_AS_ANSWER_LEAF_NODE(NODE) TrNode_parent(NODE) = (ans_node_ptr)((unsigned long int) TrNode_parent(NODE) | 0x1)
|
|
#define UNTAG_ANSWER_LEAF_NODE(NODE) ((ans_node_ptr)((unsigned long int) (NODE) & ~(0x1)))
|
|
#define IS_ANSWER_LEAF_NODE(NODE) ((unsigned long int) TrNode_parent(NODE) & 0x1)
|
|
|
|
#define MAX_NODES_PER_TRIE_LEVEL 8
|
|
#define MAX_NODES_PER_BUCKET (MAX_NODES_PER_TRIE_LEVEL / 2)
|
|
#define BASE_HASH_BUCKETS 64
|
|
#define HASH_ENTRY(ENTRY, SEED) ((((unsigned long int) ENTRY) >> NumberOfLowTagBits) & (SEED))
|
|
#ifdef GLOBAL_TRIE
|
|
#define GLOBAL_TRIE_HASH_MARK ((Term) MakeTableVarTerm(MAX_TABLE_VARS))
|
|
#define IS_GLOBAL_TRIE_HASH(NODE) (TrNode_entry(NODE) == GLOBAL_TRIE_HASH_MARK)
|
|
#endif /* GLOBAL_TRIE */
|
|
#define SUBGOAL_TRIE_HASH_MARK ((Term) MakeTableVarTerm(MAX_TABLE_VARS))
|
|
#define IS_SUBGOAL_TRIE_HASH(NODE) (TrNode_entry(NODE) == SUBGOAL_TRIE_HASH_MARK)
|
|
#define ANSWER_TRIE_HASH_MARK 0
|
|
#define IS_ANSWER_TRIE_HASH(NODE) (TrNode_instr(NODE) == ANSWER_TRIE_HASH_MARK)
|
|
|
|
#define HASH_TABLE_LOCK(NODE) ((((unsigned long int) (NODE)) >> 5) & (TABLE_LOCK_BUCKETS - 1))
|
|
#define LOCK_TABLE(NODE) LOCK(GLOBAL_table_lock(HASH_TABLE_LOCK(NODE)))
|
|
#define UNLOCK_TABLE(NODE) UNLOCK(GLOBAL_table_lock(HASH_TABLE_LOCK(NODE)))
|
|
|
|
#define STACK_PUSH_UP(ITEM, STACK) *--(STACK) = (CELL)(ITEM)
|
|
#define STACK_POP_UP(STACK) *--(STACK)
|
|
#define STACK_PUSH_DOWN(ITEM, STACK) *(STACK)++ = (CELL)(ITEM)
|
|
#define STACK_POP_DOWN(STACK) *(STACK)++
|
|
#define STACK_NOT_EMPTY(STACK, STACK_BASE) (STACK) != (STACK_BASE)
|
|
#define AUX_STACK_CHECK_EXPAND(STACK, STACK_LIMIT) if ((STACK_LIMIT) >= (STACK)) EXPAND_AUX_STACK(STACK)
|
|
#ifdef YAPOR
|
|
#define EXPAND_AUX_STACK(STACK) Yap_Error(INTERNAL_ERROR, TermNil, "stack full (STACK_CHECK_EXPAND)");
|
|
#else
|
|
#define EXPAND_AUX_STACK(STACK) STACK = expand_auxiliary_stack(STACK)
|
|
#endif /* YAPOR */
|
|
|
|
#ifdef YAPOR
|
|
#define frame_with_suspensions_not_collected(OR_FR) \
|
|
(OrFr_nearest_suspnode(OR_FR) == NULL)
|
|
#define find_dependency_node(SG_FR, LEADER_CP, DEP_ON_STACK) \
|
|
if (SgFr_gen_worker(SG_FR) == worker_id) { \
|
|
LEADER_CP = SgFr_gen_cp(SG_FR); \
|
|
DEP_ON_STACK = TRUE; \
|
|
} else { \
|
|
or_fr_ptr aux_or_fr = SgFr_gen_top_or_fr(SG_FR); \
|
|
while (! BITMAP_member(OrFr_members(aux_or_fr), worker_id)) \
|
|
aux_or_fr = OrFr_next(aux_or_fr); \
|
|
LEADER_CP = GetOrFr_node(aux_or_fr); \
|
|
DEP_ON_STACK = (LEADER_CP == SgFr_gen_cp(SG_FR)); \
|
|
}
|
|
#define find_leader_node(LEADER_CP, DEP_ON_STACK) \
|
|
{ dep_fr_ptr chain_dep_fr = LOCAL_top_dep_fr; \
|
|
while (YOUNGER_CP(DepFr_cons_cp(chain_dep_fr), LEADER_CP)) { \
|
|
if (LEADER_CP == DepFr_leader_cp(chain_dep_fr)) { \
|
|
DEP_ON_STACK |= DepFr_leader_dep_is_on_stack(chain_dep_fr); \
|
|
break; \
|
|
} else if (YOUNGER_CP(LEADER_CP, DepFr_leader_cp(chain_dep_fr))) { \
|
|
LEADER_CP = DepFr_leader_cp(chain_dep_fr); \
|
|
DEP_ON_STACK = DepFr_leader_dep_is_on_stack(chain_dep_fr); \
|
|
break; \
|
|
} \
|
|
chain_dep_fr = DepFr_next(chain_dep_fr); \
|
|
} \
|
|
}
|
|
#ifdef TIMESTAMP
|
|
#define DepFr_init_timestamp_field(DEP_FR) DepFr_timestamp(DEP_FR) = 0
|
|
#else
|
|
#define DepFr_init_timestamp_field(DEP_FR)
|
|
#endif /* TIMESTAMP */
|
|
#define YAPOR_SET_LOAD(CP_PTR) SCH_set_load(CP_PTR)
|
|
#define SgFr_init_yapor_fields(SG_FR) \
|
|
SgFr_gen_worker(SG_FR) = worker_id; \
|
|
SgFr_gen_top_or_fr(SG_FR) = LOCAL_top_or_fr
|
|
#define DepFr_init_yapor_fields(DEP_FR, DEP_ON_STACK, TOP_OR_FR) \
|
|
DepFr_leader_dep_is_on_stack(DEP_FR) = DEP_ON_STACK; \
|
|
DepFr_top_or_fr(DEP_FR) = TOP_OR_FR; \
|
|
DepFr_init_timestamp_field(DEP_FR)
|
|
#else
|
|
#define find_dependency_node(SG_FR, LEADER_CP, DEP_ON_STACK) \
|
|
LEADER_CP = SgFr_gen_cp(SG_FR); \
|
|
DEP_ON_STACK = TRUE
|
|
#define find_leader_node(LEADER_CP, DEP_ON_STACK) \
|
|
{ dep_fr_ptr chain_dep_fr = LOCAL_top_dep_fr; \
|
|
while (YOUNGER_CP(DepFr_cons_cp(chain_dep_fr), LEADER_CP)) { \
|
|
if (EQUAL_OR_YOUNGER_CP(LEADER_CP, DepFr_leader_cp(chain_dep_fr))) { \
|
|
LEADER_CP = DepFr_leader_cp(chain_dep_fr); \
|
|
break; \
|
|
} \
|
|
chain_dep_fr = DepFr_next(chain_dep_fr); \
|
|
} \
|
|
}
|
|
#define YAPOR_SET_LOAD(CP_PTR)
|
|
#define SgFr_init_yapor_fields(SG_FR)
|
|
#define DepFr_init_yapor_fields(DEP_FR, DEP_ON_STACK, TOP_OR_FR)
|
|
#endif /* YAPOR */
|
|
|
|
#ifdef TABLE_LOCK_AT_ENTRY_LEVEL
|
|
#define TabEnt_init_lock_field(TAB_ENT) \
|
|
INIT_LOCK(TabEnt_lock(TAB_ENT))
|
|
#define SgHash_init_next_field(HASH, TAB_ENT) \
|
|
Hash_next(HASH) = TabEnt_hash_chain(TAB_ENT); \
|
|
TabEnt_hash_chain(TAB_ENT) = HASH
|
|
#define AnsHash_init_next_field(HASH, SG_FR) \
|
|
Hash_next(HASH) = SgFr_hash_chain(SG_FR); \
|
|
SgFr_hash_chain(SG_FR) = HASH
|
|
#else
|
|
#define TabEnt_init_lock_field(TAB_ENT)
|
|
#define SgHash_init_next_field(HASH, TAB_ENT) \
|
|
LOCK(TabEnt_lock(TAB_ENT)); \
|
|
Hash_next(HASH) = TabEnt_hash_chain(TAB_ENT); \
|
|
TabEnt_hash_chain(TAB_ENT) = HASH; \
|
|
UNLOCK(TabEnt_lock(TAB_ENT))
|
|
#define AnsHash_init_next_field(HASH, SG_FR) \
|
|
LOCK(SgFr_lock(SG_FR)); \
|
|
Hash_next(HASH) = SgFr_hash_chain(SG_FR); \
|
|
SgFr_hash_chain(SG_FR) = HASH; \
|
|
UNLOCK(SgFr_lock(SG_FR))
|
|
#endif /* TABLE_LOCK_AT_ENTRY_LEVEL */
|
|
|
|
#ifdef TABLE_LOCK_AT_NODE_LEVEL
|
|
#define TrNode_init_lock_field(NODE) \
|
|
INIT_LOCK(TrNode_lock(NODE))
|
|
#else
|
|
#define TrNode_init_lock_field(NODE)
|
|
#endif /* TABLE_LOCK_AT_NODE_LEVEL */
|
|
|
|
#define new_table_entry(TAB_ENT, PRED_ENTRY, ATOM, ARITY) \
|
|
{ register sg_node_ptr sg_node; \
|
|
new_subgoal_trie_node(sg_node, 0, NULL, NULL, NULL); \
|
|
ALLOC_TABLE_ENTRY(TAB_ENT); \
|
|
TabEnt_init_lock_field(TAB_ENT); \
|
|
TabEnt_pe(TAB_ENT) = PRED_ENTRY; \
|
|
TabEnt_atom(TAB_ENT) = ATOM; \
|
|
TabEnt_arity(TAB_ENT) = ARITY; \
|
|
TabEnt_mode(TAB_ENT) = 0; \
|
|
TabEnt_subgoal_trie(TAB_ENT) = sg_node; \
|
|
TabEnt_hash_chain(TAB_ENT) = NULL; \
|
|
TabEnt_next(TAB_ENT) = GLOBAL_root_tab_ent; \
|
|
GLOBAL_root_tab_ent = TAB_ENT; \
|
|
}
|
|
|
|
#define new_subgoal_frame(SG_FR, CODE) \
|
|
{ register ans_node_ptr ans_node; \
|
|
new_answer_trie_node(ans_node, 0, 0, NULL, NULL, NULL); \
|
|
ALLOC_SUBGOAL_FRAME(SG_FR); \
|
|
INIT_LOCK(SgFr_lock(SG_FR)); \
|
|
SgFr_code(SG_FR) = CODE; \
|
|
SgFr_state(SG_FR) = ready; \
|
|
SgFr_hash_chain(SG_FR) = NULL; \
|
|
SgFr_answer_trie(SG_FR) = ans_node; \
|
|
SgFr_first_answer(SG_FR) = NULL; \
|
|
SgFr_last_answer(SG_FR) = NULL; \
|
|
}
|
|
#define init_subgoal_frame(SG_FR) \
|
|
{ SgFr_init_yapor_fields(SG_FR); \
|
|
SgFr_state(SG_FR) = evaluating; \
|
|
SgFr_next(SG_FR) = LOCAL_top_sg_fr; \
|
|
LOCAL_top_sg_fr = SG_FR; \
|
|
}
|
|
|
|
#define new_dependency_frame(DEP_FR, DEP_ON_STACK, TOP_OR_FR, LEADER_CP, CONS_CP, SG_FR, NEXT) \
|
|
ALLOC_DEPENDENCY_FRAME(DEP_FR); \
|
|
INIT_LOCK(DepFr_lock(DEP_FR)); \
|
|
DepFr_init_yapor_fields(DEP_FR, DEP_ON_STACK, TOP_OR_FR); \
|
|
DepFr_backchain_cp(DEP_FR) = NULL; \
|
|
DepFr_leader_cp(DEP_FR) = NORM_CP(LEADER_CP); \
|
|
DepFr_cons_cp(DEP_FR) = NORM_CP(CONS_CP); \
|
|
/* start with TrNode_child(DepFr_last_answer(DEP_FR)) pointing to SgFr_first_answer(SG_FR) */ \
|
|
DepFr_last_answer(DEP_FR) = (ans_node_ptr) ((unsigned long int) (SG_FR) + \
|
|
(unsigned long int) (&SgFr_first_answer((sg_fr_ptr)DEP_FR)) - \
|
|
(unsigned long int) (&TrNode_child((ans_node_ptr)DEP_FR))); \
|
|
DepFr_next(DEP_FR) = NEXT
|
|
|
|
#define new_suspension_frame(SUSP_FR, TOP_OR_FR_ON_STACK, TOP_DEP, TOP_SG, \
|
|
H_REG, B_REG, TR_REG, H_SIZE, B_SIZE, TR_SIZE) \
|
|
ALLOC_SUSPENSION_FRAME(SUSP_FR); \
|
|
SuspFr_top_or_fr_on_stack(SUSP_FR) = TOP_OR_FR_ON_STACK; \
|
|
SuspFr_top_dep_fr(SUSP_FR) = TOP_DEP; \
|
|
SuspFr_top_sg_fr(SUSP_FR) = TOP_SG; \
|
|
SuspFr_global_reg(SUSP_FR) = (void *) (H_REG); \
|
|
SuspFr_local_reg(SUSP_FR) = (void *) (B_REG); \
|
|
SuspFr_trail_reg(SUSP_FR) = (void *) (TR_REG); \
|
|
ALLOC_BLOCK(SuspFr_global_start(SUSP_FR), H_SIZE + B_SIZE + TR_SIZE); \
|
|
SuspFr_local_start(SUSP_FR) = SuspFr_global_start(SUSP_FR) + H_SIZE; \
|
|
SuspFr_trail_start(SUSP_FR) = SuspFr_local_start(SUSP_FR) + B_SIZE; \
|
|
SuspFr_global_size(SUSP_FR) = H_SIZE; \
|
|
SuspFr_local_size(SUSP_FR) = B_SIZE; \
|
|
SuspFr_trail_size(SUSP_FR) = TR_SIZE; \
|
|
memcpy(SuspFr_global_start(SUSP_FR), SuspFr_global_reg(SUSP_FR), H_SIZE); \
|
|
memcpy(SuspFr_local_start(SUSP_FR), SuspFr_local_reg(SUSP_FR), B_SIZE); \
|
|
memcpy(SuspFr_trail_start(SUSP_FR), SuspFr_trail_reg(SUSP_FR), TR_SIZE)
|
|
|
|
#define new_subgoal_trie_node(NODE, ENTRY, CHILD, PARENT, NEXT) \
|
|
ALLOC_SUBGOAL_TRIE_NODE(NODE); \
|
|
TrNode_entry(NODE) = ENTRY; \
|
|
TrNode_init_lock_field(NODE); \
|
|
TrNode_child(NODE) = CHILD; \
|
|
TrNode_parent(NODE) = PARENT; \
|
|
TrNode_next(NODE) = NEXT
|
|
|
|
#define new_answer_trie_node(NODE, INSTR, ENTRY, CHILD, PARENT, NEXT) \
|
|
ALLOC_ANSWER_TRIE_NODE(NODE); \
|
|
TrNode_instr(NODE) = INSTR; \
|
|
TrNode_entry(NODE) = ENTRY; \
|
|
TrNode_init_lock_field(NODE); \
|
|
TrNode_child(NODE) = CHILD; \
|
|
TrNode_parent(NODE) = PARENT; \
|
|
TrNode_next(NODE) = NEXT
|
|
|
|
#define new_global_trie_node(NODE, ENTRY, CHILD, PARENT, NEXT) \
|
|
ALLOC_GLOBAL_TRIE_NODE(NODE); \
|
|
TrNode_entry(NODE) = ENTRY; \
|
|
TrNode_child(NODE) = CHILD; \
|
|
TrNode_parent(NODE) = PARENT; \
|
|
TrNode_next(NODE) = NEXT
|
|
|
|
#define new_subgoal_trie_hash(HASH, NUM_NODES, TAB_ENT) \
|
|
ALLOC_SUBGOAL_TRIE_HASH(HASH); \
|
|
Hash_mark(HASH) = SUBGOAL_TRIE_HASH_MARK; \
|
|
Hash_num_buckets(HASH) = BASE_HASH_BUCKETS; \
|
|
ALLOC_HASH_BUCKETS(Hash_buckets(HASH), BASE_HASH_BUCKETS); \
|
|
Hash_num_nodes(HASH) = NUM_NODES; \
|
|
SgHash_init_next_field(HASH, TAB_ENT)
|
|
|
|
#define new_answer_trie_hash(HASH, NUM_NODES, SG_FR) \
|
|
ALLOC_ANSWER_TRIE_HASH(HASH); \
|
|
Hash_mark(HASH) = ANSWER_TRIE_HASH_MARK; \
|
|
Hash_num_buckets(HASH) = BASE_HASH_BUCKETS; \
|
|
ALLOC_HASH_BUCKETS(Hash_buckets(HASH), BASE_HASH_BUCKETS); \
|
|
Hash_num_nodes(HASH) = NUM_NODES; \
|
|
AnsHash_init_next_field(HASH, SG_FR)
|
|
|
|
#define new_global_trie_hash(HASH, NUM_NODES) \
|
|
ALLOC_GLOBAL_TRIE_HASH(HASH); \
|
|
Hash_mark(HASH) = GLOBAL_TRIE_HASH_MARK; \
|
|
Hash_num_buckets(HASH) = BASE_HASH_BUCKETS; \
|
|
ALLOC_HASH_BUCKETS(Hash_buckets(HASH), BASE_HASH_BUCKETS); \
|
|
Hash_num_nodes(HASH) = NUM_NODES
|
|
|
|
#ifdef LIMIT_TABLING
|
|
#define insert_into_global_sg_fr_list(SG_FR) \
|
|
SgFr_previous(SG_FR) = GLOBAL_last_sg_fr; \
|
|
SgFr_next(SG_FR) = NULL; \
|
|
if (GLOBAL_first_sg_fr == NULL) \
|
|
GLOBAL_first_sg_fr = SG_FR; \
|
|
else \
|
|
SgFr_next(GLOBAL_last_sg_fr) = SG_FR; \
|
|
GLOBAL_last_sg_fr = SG_FR
|
|
#define remove_from_global_sg_fr_list(SG_FR) \
|
|
if (SgFr_previous(SG_FR)) { \
|
|
if ((SgFr_next(SgFr_previous(SG_FR)) = SgFr_next(SG_FR)) != NULL) \
|
|
SgFr_previous(SgFr_next(SG_FR)) = SgFr_previous(SG_FR); \
|
|
else \
|
|
GLOBAL_last_sg_fr = SgFr_previous(SG_FR); \
|
|
} else { \
|
|
if ((GLOBAL_first_sg_fr = SgFr_next(SG_FR)) != NULL) \
|
|
SgFr_previous(SgFr_next(SG_FR)) = NULL; \
|
|
else \
|
|
GLOBAL_last_sg_fr = NULL; \
|
|
} \
|
|
if (GLOBAL_check_sg_fr == SG_FR) \
|
|
GLOBAL_check_sg_fr = SgFr_previous(SG_FR)
|
|
#else
|
|
#define insert_into_global_sg_fr_list(SG_FR)
|
|
#define remove_from_global_sg_fr_list(SG_FR)
|
|
#endif /* LIMIT_TABLING */
|
|
|
|
|
|
|
|
/******************************
|
|
** Inline funcions **
|
|
******************************/
|
|
|
|
static inline
|
|
CELL *expand_auxiliary_stack(CELL *stack) {
|
|
void *old_top = Yap_TrailTop;
|
|
INFORMATION_MESSAGE("Expanding trail in 64 Kbytes");
|
|
if (! Yap_growtrail(64 * 1024L, TRUE)) { /* TRUE means 'contiguous_only' */
|
|
Yap_Error(OUT_OF_TRAIL_ERROR, TermNil, "stack full (STACK_CHECK_EXPAND)");
|
|
return NULL;
|
|
} else {
|
|
UInt diff = (void *)Yap_TrailTop - old_top;
|
|
CELL *new_stack = (CELL *)((void *)stack + diff);
|
|
memmove((void *)new_stack, (void *)stack, old_top - (void *)stack);
|
|
return new_stack;
|
|
}
|
|
}
|
|
|
|
|
|
static inline
|
|
void adjust_freeze_registers(void) {
|
|
B_FZ = DepFr_cons_cp(LOCAL_top_dep_fr);
|
|
H_FZ = B_FZ->cp_h;
|
|
TR_FZ = B_FZ->cp_tr;
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void mark_as_completed(sg_fr_ptr sg_fr) {
|
|
LOCK(SgFr_lock(sg_fr));
|
|
SgFr_state(sg_fr) = complete;
|
|
UNLOCK(SgFr_lock(sg_fr));
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void unbind_variables(tr_fr_ptr unbind_tr, tr_fr_ptr end_tr) {
|
|
#ifdef TABLING_ERRORS
|
|
if (unbind_tr < end_tr)
|
|
TABLING_ERROR_MESSAGE("unbind_tr < end_tr (function unbind_variables)");
|
|
#endif /* TABLING_ERRORS */
|
|
/* unbind loop */
|
|
while (unbind_tr != end_tr) {
|
|
CELL ref = (CELL) TrailTerm(--unbind_tr);
|
|
/* check for global or local variables */
|
|
if (IsVarTerm(ref)) {
|
|
/* unbind variable */
|
|
RESET_VARIABLE(ref);
|
|
} else if (IsPairTerm(ref)) {
|
|
ref = (CELL) RepPair(ref);
|
|
if (IN_BETWEEN(Yap_TrailBase, ref, Yap_TrailTop)) {
|
|
/* avoid frozen segments */
|
|
unbind_tr = (tr_fr_ptr) ref;
|
|
#ifdef TABLING_ERRORS
|
|
if (unbind_tr > (tr_fr_ptr) Yap_TrailTop)
|
|
TABLING_ERROR_MESSAGE("unbind_tr > Yap_TrailTop (function unbind_variables)");
|
|
if (unbind_tr < end_tr)
|
|
TABLING_ERROR_MESSAGE("unbind_tr < end_tr (function unbind_variables)");
|
|
#endif /* TABLING_ERRORS */
|
|
}
|
|
#ifdef MULTI_ASSIGNMENT_VARIABLES
|
|
} else {
|
|
CELL *aux_ptr = RepAppl(ref);
|
|
--unbind_tr;
|
|
Term aux_val = TrailVal(unbind_tr);
|
|
*aux_ptr = aux_val;
|
|
#endif /* MULTI_ASSIGNMENT_VARIABLES */
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void rebind_variables(tr_fr_ptr rebind_tr, tr_fr_ptr end_tr) {
|
|
#ifdef TABLING_ERRORS
|
|
if (rebind_tr < end_tr)
|
|
TABLING_ERROR_MESSAGE("rebind_tr < end_tr (function rebind_variables)");
|
|
#endif /* TABLING_ERRORS */
|
|
/* rebind loop */
|
|
Yap_NEW_MAHASH((ma_h_inner_struct *)H);
|
|
while (rebind_tr != end_tr) {
|
|
CELL ref = (CELL) TrailTerm(--rebind_tr);
|
|
/* check for global or local variables */
|
|
if (IsVarTerm(ref)) {
|
|
/* rebind variable */
|
|
*((CELL *)ref) = TrailVal(rebind_tr);
|
|
} else if (IsPairTerm(ref)) {
|
|
ref = (CELL) RepPair(ref);
|
|
if (IN_BETWEEN(Yap_TrailBase, ref, Yap_TrailTop)) {
|
|
/* avoid frozen segments */
|
|
rebind_tr = (tr_fr_ptr) ref;
|
|
#ifdef TABLING_ERRORS
|
|
if (rebind_tr > (tr_fr_ptr) Yap_TrailTop)
|
|
TABLING_ERROR_MESSAGE("rebind_tr > Yap_TrailTop (function rebind_variables)");
|
|
if (rebind_tr < end_tr)
|
|
TABLING_ERROR_MESSAGE("rebind_tr < end_tr (function rebind_variables)");
|
|
#endif /* TABLING_ERRORS */
|
|
}
|
|
#ifdef MULTI_ASSIGNMENT_VARIABLES
|
|
} else {
|
|
CELL *cell_ptr = RepAppl(ref);
|
|
if (!Yap_lookup_ma_var(cell_ptr)) {
|
|
/* first time we found the variable, let's put the new value */
|
|
*cell_ptr = TrailVal(rebind_tr);
|
|
}
|
|
--rebind_tr;
|
|
#endif /* MULTI_ASSIGNMENT_VARIABLES */
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void restore_bindings(tr_fr_ptr unbind_tr, tr_fr_ptr rebind_tr) {
|
|
CELL ref;
|
|
tr_fr_ptr end_tr;
|
|
|
|
#ifdef TABLING_ERRORS
|
|
if (unbind_tr < rebind_tr)
|
|
TABLING_ERROR_MESSAGE("unbind_tr < rebind_tr (function restore_bindings)");
|
|
#endif /* TABLING_ERRORS */
|
|
end_tr = rebind_tr;
|
|
Yap_NEW_MAHASH((ma_h_inner_struct *)H);
|
|
while (unbind_tr != end_tr) {
|
|
/* unbind loop */
|
|
while (unbind_tr > end_tr) {
|
|
ref = (CELL) TrailTerm(--unbind_tr);
|
|
if (IsVarTerm(ref)) {
|
|
RESET_VARIABLE(ref);
|
|
} else if (IsPairTerm(ref)) {
|
|
ref = (CELL) RepPair(ref);
|
|
if (IN_BETWEEN(Yap_TrailBase, ref, Yap_TrailTop)) {
|
|
/* avoid frozen segments */
|
|
unbind_tr = (tr_fr_ptr) ref;
|
|
#ifdef TABLING_ERRORS
|
|
if (unbind_tr > (tr_fr_ptr) Yap_TrailTop)
|
|
TABLING_ERROR_MESSAGE("unbind_tr > Yap_TrailTop (function restore_bindings)");
|
|
#endif /* TABLING_ERRORS */
|
|
}
|
|
#ifdef MULTI_ASSIGNMENT_VARIABLES
|
|
} else if (IsApplTerm(ref)) {
|
|
CELL *pt = RepAppl(ref);
|
|
|
|
/* AbsAppl means */
|
|
/* multi-assignment variable */
|
|
/* so that the upper cell is the old value */
|
|
--unbind_tr;
|
|
if (!Yap_lookup_ma_var(pt)) {
|
|
pt[0] = TrailVal(unbind_tr);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
/* look for end */
|
|
while (unbind_tr < end_tr) {
|
|
ref = (CELL) TrailTerm(--end_tr);
|
|
if (IsPairTerm(ref)) {
|
|
ref = (CELL) RepPair(ref);
|
|
if (IN_BETWEEN(Yap_TrailBase, ref, Yap_TrailTop)) {
|
|
/* avoid frozen segments */
|
|
end_tr = (tr_fr_ptr) ref;
|
|
#ifdef TABLING_ERRORS
|
|
if (end_tr > (tr_fr_ptr) Yap_TrailTop)
|
|
TABLING_ERROR_MESSAGE("end_tr > Yap_TrailTop (function restore_bindings)");
|
|
#endif /* TABLING_ERRORS */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* rebind loop */
|
|
while (rebind_tr != end_tr) {
|
|
ref = (CELL) TrailTerm(--rebind_tr);
|
|
if (IsVarTerm(ref)) {
|
|
*((CELL *)ref) = TrailVal(rebind_tr);
|
|
} else if (IsPairTerm(ref)) {
|
|
ref = (CELL) RepPair(ref);
|
|
if (IN_BETWEEN(Yap_TrailBase, ref, Yap_TrailTop)) {
|
|
/* avoid frozen segments */
|
|
rebind_tr = (tr_fr_ptr) ref;
|
|
#ifdef TABLING_ERRORS
|
|
if (rebind_tr > (tr_fr_ptr) Yap_TrailTop)
|
|
TABLING_ERROR_MESSAGE("rebind_tr > Yap_TrailTop (function restore_bindings)");
|
|
if (rebind_tr < end_tr)
|
|
TABLING_ERROR_MESSAGE("rebind_tr < end_tr (function restore_bindings)");
|
|
#endif /* TABLING_ERRORS */
|
|
}
|
|
#ifdef MULTI_ASSIGNMENT_VARIABLES
|
|
} else {
|
|
CELL *cell_ptr = RepAppl(ref);
|
|
/* first time we found the variable, let's put the new value */
|
|
*cell_ptr = TrailVal(rebind_tr);
|
|
--rebind_tr;
|
|
#endif /* MULTI_ASSIGNMENT_VARIABLES */
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void abolish_incomplete_subgoals(choiceptr prune_cp) {
|
|
#ifdef YAPOR
|
|
if (EQUAL_OR_YOUNGER_CP(GetOrFr_node(LOCAL_top_susp_or_fr), prune_cp))
|
|
pruning_over_tabling_data_structures();
|
|
#endif /* YAPOR */
|
|
|
|
if (EQUAL_OR_YOUNGER_CP(DepFr_cons_cp(LOCAL_top_dep_fr), prune_cp)) {
|
|
#ifdef YAPOR
|
|
if (PARALLEL_EXECUTION_MODE)
|
|
pruning_over_tabling_data_structures();
|
|
#endif /* YAPOR */
|
|
do {
|
|
dep_fr_ptr dep_fr = LOCAL_top_dep_fr;
|
|
LOCAL_top_dep_fr = DepFr_next(dep_fr);
|
|
FREE_DEPENDENCY_FRAME(dep_fr);
|
|
} while (EQUAL_OR_YOUNGER_CP(DepFr_cons_cp(LOCAL_top_dep_fr), prune_cp));
|
|
adjust_freeze_registers();
|
|
}
|
|
|
|
while (LOCAL_top_sg_fr && EQUAL_OR_YOUNGER_CP(SgFr_gen_cp(LOCAL_top_sg_fr), prune_cp)) {
|
|
sg_fr_ptr sg_fr;
|
|
#ifdef YAPOR
|
|
if (PARALLEL_EXECUTION_MODE)
|
|
pruning_over_tabling_data_structures();
|
|
#endif /* YAPOR */
|
|
sg_fr = LOCAL_top_sg_fr;
|
|
LOCAL_top_sg_fr = SgFr_next(sg_fr);
|
|
LOCK(SgFr_lock(sg_fr));
|
|
if (SgFr_first_answer(sg_fr) == NULL) {
|
|
/* no answers --> ready */
|
|
SgFr_state(sg_fr) = ready;
|
|
UNLOCK(SgFr_lock(sg_fr));
|
|
} else if (SgFr_first_answer(sg_fr) == SgFr_answer_trie(sg_fr)) {
|
|
/* yes answer --> complete */
|
|
#ifndef TABLING_EARLY_COMPLETION
|
|
/* with early completion, at this point the subgoal should be already completed */
|
|
SgFr_state(sg_fr) = complete;
|
|
#endif /* TABLING_EARLY_COMPLETION */
|
|
UNLOCK(SgFr_lock(sg_fr));
|
|
} else {
|
|
/* answers --> incomplete/ready */
|
|
#ifdef INCOMPLETE_TABLING
|
|
SgFr_state(sg_fr) = incomplete;
|
|
UNLOCK(SgFr_lock(sg_fr));
|
|
#else
|
|
ans_node_ptr node;
|
|
SgFr_state(sg_fr) = ready;
|
|
free_answer_trie_hash_chain(SgFr_hash_chain(sg_fr));
|
|
SgFr_hash_chain(sg_fr) = NULL;
|
|
SgFr_first_answer(sg_fr) = NULL;
|
|
SgFr_last_answer(sg_fr) = NULL;
|
|
node = TrNode_child(SgFr_answer_trie(sg_fr));
|
|
TrNode_child(SgFr_answer_trie(sg_fr)) = NULL;
|
|
UNLOCK(SgFr_lock(sg_fr));
|
|
free_answer_trie_branch(node, TRAVERSE_POSITION_FIRST);
|
|
#endif /* INCOMPLETE_TABLING */
|
|
}
|
|
#ifdef LIMIT_TABLING
|
|
insert_into_global_sg_fr_list(sg_fr);
|
|
#endif /* LIMIT_TABLING */
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void free_subgoal_trie_hash_chain(sg_hash_ptr hash) {
|
|
while (hash) {
|
|
sg_node_ptr chain_node, *bucket, *last_bucket;
|
|
sg_hash_ptr next_hash;
|
|
|
|
bucket = Hash_buckets(hash);
|
|
last_bucket = bucket + Hash_num_buckets(hash);
|
|
while (! *bucket)
|
|
bucket++;
|
|
chain_node = *bucket;
|
|
TrNode_child(TrNode_parent(chain_node)) = chain_node;
|
|
while (++bucket != last_bucket) {
|
|
if (*bucket) {
|
|
while (TrNode_next(chain_node))
|
|
chain_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
chain_node = *bucket;
|
|
}
|
|
}
|
|
next_hash = Hash_next(hash);
|
|
FREE_HASH_BUCKETS(Hash_buckets(hash));
|
|
FREE_SUBGOAL_TRIE_HASH(hash);
|
|
hash = next_hash;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void free_answer_trie_hash_chain(ans_hash_ptr hash) {
|
|
while (hash) {
|
|
ans_node_ptr chain_node, *bucket, *last_bucket;
|
|
ans_hash_ptr next_hash;
|
|
|
|
bucket = Hash_buckets(hash);
|
|
last_bucket = bucket + Hash_num_buckets(hash);
|
|
while (! *bucket)
|
|
bucket++;
|
|
chain_node = *bucket;
|
|
TrNode_child(UNTAG_ANSWER_LEAF_NODE(TrNode_parent(chain_node))) = chain_node;
|
|
while (++bucket != last_bucket) {
|
|
if (*bucket) {
|
|
while (TrNode_next(chain_node))
|
|
chain_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
chain_node = *bucket;
|
|
}
|
|
}
|
|
next_hash = Hash_next(hash);
|
|
FREE_HASH_BUCKETS(Hash_buckets(hash));
|
|
FREE_ANSWER_TRIE_HASH(hash);
|
|
hash = next_hash;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
static inline
|
|
choiceptr create_cp_and_freeze(void) {
|
|
choiceptr freeze_cp;
|
|
|
|
// initialize and store freeze choice point
|
|
// freeze_cp = (NORM_CP(YENV) - 1);
|
|
freeze_cp = (NORM_CP(YENV) - 2);
|
|
HBREG = H;
|
|
store_yaam_reg_cpdepth(freeze_cp);
|
|
freeze_cp->cp_tr = TR;
|
|
freeze_cp->cp_ap = (yamop *)(TRUSTFAILCODE);
|
|
freeze_cp->cp_h = H;
|
|
freeze_cp->cp_b = B;
|
|
freeze_cp->cp_env = ENV;
|
|
freeze_cp->cp_cp = CPREG;
|
|
// set_cut((CELL *)freeze_cp, B);
|
|
B = freeze_cp;
|
|
SET_BB(B);
|
|
// adjust freeze registers
|
|
B_FZ = freeze_cp;
|
|
H_FZ = H;
|
|
TR_FZ = TR;
|
|
return freeze_cp;
|
|
}
|
|
*/
|
|
|
|
|
|
static inline
|
|
choiceptr freeze_current_cp(void) {
|
|
choiceptr freeze_cp = B;
|
|
|
|
B_FZ = freeze_cp;
|
|
H_FZ = freeze_cp->cp_h;
|
|
TR_FZ = freeze_cp->cp_tr;
|
|
B = B->cp_b;
|
|
HB = B->cp_h;
|
|
return freeze_cp;
|
|
}
|
|
|
|
|
|
static inline
|
|
void resume_frozen_cp(choiceptr frozen_cp) {
|
|
restore_bindings(TR, frozen_cp->cp_tr);
|
|
B = frozen_cp;
|
|
TR = TR_FZ;
|
|
TRAIL_LINK(B->cp_tr);
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void abolish_all_frozen_cps(void) {
|
|
B_FZ = (choiceptr) Yap_LocalBase;
|
|
H_FZ = (CELL *) Yap_GlobalBase;
|
|
TR_FZ = (tr_fr_ptr) Yap_TrailBase;
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef YAPOR
|
|
static inline
|
|
void pruning_over_tabling_data_structures(void) {
|
|
Yap_Error(INTERNAL_ERROR, TermNil, "pruning over tabling data structures");
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void collect_suspension_frames(or_fr_ptr or_fr) {
|
|
int depth;
|
|
or_fr_ptr *susp_ptr;
|
|
|
|
#ifdef OPTYAP_ERRORS
|
|
if (IS_UNLOCKED(or_fr))
|
|
OPTYAP_ERROR_MESSAGE("or_fr unlocked (collect_suspension_frames)");
|
|
if (OrFr_suspensions(or_fr) == NULL)
|
|
OPTYAP_ERROR_MESSAGE("OrFr_suspensions(or_fr) == NULL (collect_suspension_frames)");
|
|
#endif /* OPTYAP_ERRORS */
|
|
|
|
/* order collected suspension frames by depth */
|
|
depth = OrFr_depth(or_fr);
|
|
susp_ptr = & LOCAL_top_susp_or_fr;
|
|
while (OrFr_depth(*susp_ptr) > depth)
|
|
susp_ptr = & OrFr_nearest_suspnode(*susp_ptr);
|
|
OrFr_nearest_suspnode(or_fr) = *susp_ptr;
|
|
*susp_ptr = or_fr;
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
#ifdef TIMESTAMP_CHECK
|
|
susp_fr_ptr suspension_frame_to_resume(or_fr_ptr susp_or_fr, long timestamp) {
|
|
#else
|
|
susp_fr_ptr suspension_frame_to_resume(or_fr_ptr susp_or_fr) {
|
|
#endif /* TIMESTAMP_CHECK */
|
|
choiceptr top_cp;
|
|
susp_fr_ptr *susp_ptr, susp_fr;
|
|
dep_fr_ptr dep_fr;
|
|
|
|
top_cp = GetOrFr_node(susp_or_fr);
|
|
susp_ptr = & OrFr_suspensions(susp_or_fr);
|
|
susp_fr = *susp_ptr;
|
|
while (susp_fr) {
|
|
dep_fr = SuspFr_top_dep_fr(susp_fr);
|
|
do {
|
|
if (TrNode_child(DepFr_last_answer(dep_fr))) {
|
|
/* unconsumed answers in susp_fr */
|
|
*susp_ptr = SuspFr_next(susp_fr);
|
|
return susp_fr;
|
|
}
|
|
#ifdef TIMESTAMP_CHECK
|
|
DepFr_timestamp(dep_fr) = timestamp;
|
|
#endif /* TIMESTAMP_CHECK */
|
|
dep_fr = DepFr_next(dep_fr);
|
|
#ifdef TIMESTAMP_CHECK
|
|
} while (timestamp > DepFr_timestamp(dep_fr) && YOUNGER_CP(DepFr_cons_cp(dep_fr), top_cp));
|
|
#else
|
|
} while (YOUNGER_CP(DepFr_cons_cp(dep_fr), top_cp));
|
|
#endif /* TIMESTAMP_CHECK */
|
|
susp_ptr = & SuspFr_next(susp_fr);
|
|
susp_fr = *susp_ptr;
|
|
}
|
|
/* no suspension frame with unconsumed answers */
|
|
return NULL;
|
|
}
|
|
#endif /* YAPOR */
|
|
|
|
|
|
#ifdef TABLING_INNER_CUTS
|
|
static inline
|
|
void CUT_store_tg_answer(or_fr_ptr or_frame, ans_node_ptr ans_node, choiceptr gen_cp, int ltt) {
|
|
tg_sol_fr_ptr tg_sol_fr, *solution_ptr, next, ltt_next;
|
|
tg_ans_fr_ptr tg_ans_fr;
|
|
|
|
solution_ptr = & OrFr_tg_solutions(or_frame);
|
|
while (*solution_ptr && YOUNGER_CP(gen_cp, TgSolFr_gen_cp(*solution_ptr))) {
|
|
solution_ptr = & TgSolFr_next(*solution_ptr);
|
|
}
|
|
if (*solution_ptr && gen_cp == TgSolFr_gen_cp(*solution_ptr)) {
|
|
if (ltt >= TgSolFr_ltt(*solution_ptr)) {
|
|
while (*solution_ptr && ltt > TgSolFr_ltt(*solution_ptr)) {
|
|
solution_ptr = & TgSolFr_ltt_next(*solution_ptr);
|
|
}
|
|
if (*solution_ptr && ltt == TgSolFr_ltt(*solution_ptr)) {
|
|
tg_ans_fr = TgSolFr_first(*solution_ptr);
|
|
if (TgAnsFr_free_slot(tg_ans_fr) == TG_ANSWER_SLOTS) {
|
|
ALLOC_TG_ANSWER_FRAME(tg_ans_fr);
|
|
TgAnsFr_free_slot(tg_ans_fr) = 1;
|
|
TgAnsFr_answer(tg_ans_fr, 0) = ans_node;
|
|
TgAnsFr_next(tg_ans_fr) = TgSolFr_first(*solution_ptr);
|
|
TgSolFr_first(*solution_ptr) = tg_ans_fr;
|
|
} else {
|
|
TgAnsFr_answer(tg_ans_fr, TgAnsFr_free_slot(tg_ans_fr)) = ans_node;
|
|
TgAnsFr_free_slot(tg_ans_fr)++;
|
|
}
|
|
return;
|
|
}
|
|
ltt_next = *solution_ptr;
|
|
next = NULL;
|
|
} else {
|
|
ltt_next = *solution_ptr;
|
|
next = TgSolFr_next(*solution_ptr);
|
|
}
|
|
} else {
|
|
ltt_next = NULL;
|
|
next = *solution_ptr;
|
|
}
|
|
ALLOC_TG_ANSWER_FRAME(tg_ans_fr);
|
|
TgAnsFr_free_slot(tg_ans_fr) = 1;
|
|
TgAnsFr_answer(tg_ans_fr, 0) = ans_node;
|
|
TgAnsFr_next(tg_ans_fr) = NULL;
|
|
ALLOC_TG_SOLUTION_FRAME(tg_sol_fr);
|
|
TgSolFr_gen_cp(tg_sol_fr) = gen_cp;
|
|
TgSolFr_ltt(tg_sol_fr) = ltt;
|
|
TgSolFr_first(tg_sol_fr) = tg_ans_fr;
|
|
TgSolFr_last(tg_sol_fr) = tg_ans_fr;
|
|
TgSolFr_ltt_next(tg_sol_fr) = ltt_next;
|
|
TgSolFr_next(tg_sol_fr) = next;
|
|
*solution_ptr = tg_sol_fr;
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
tg_sol_fr_ptr CUT_store_tg_answers(or_fr_ptr or_frame, tg_sol_fr_ptr new_solution, int ltt) {
|
|
tg_sol_fr_ptr *old_solution_ptr, next_new_solution;
|
|
choiceptr node, gen_cp;
|
|
|
|
old_solution_ptr = & OrFr_tg_solutions(or_frame);
|
|
node = GetOrFr_node(or_frame);
|
|
while (new_solution && YOUNGER_CP(node, TgSolFr_gen_cp(new_solution))) {
|
|
next_new_solution = TgSolFr_next(new_solution);
|
|
gen_cp = TgSolFr_gen_cp(new_solution);
|
|
while (*old_solution_ptr && YOUNGER_CP(gen_cp, TgSolFr_gen_cp(*old_solution_ptr))) {
|
|
old_solution_ptr = & TgSolFr_next(*old_solution_ptr);
|
|
}
|
|
if (*old_solution_ptr && gen_cp == TgSolFr_gen_cp(*old_solution_ptr)) {
|
|
if (ltt >= TgSolFr_ltt(*old_solution_ptr)) {
|
|
tg_sol_fr_ptr *ltt_next_old_solution_ptr;
|
|
ltt_next_old_solution_ptr = old_solution_ptr;
|
|
while (*ltt_next_old_solution_ptr && ltt > TgSolFr_ltt(*ltt_next_old_solution_ptr)) {
|
|
ltt_next_old_solution_ptr = & TgSolFr_ltt_next(*ltt_next_old_solution_ptr);
|
|
}
|
|
if (*ltt_next_old_solution_ptr && ltt == TgSolFr_ltt(*ltt_next_old_solution_ptr)) {
|
|
TgAnsFr_next(TgSolFr_last(*ltt_next_old_solution_ptr)) = TgSolFr_first(new_solution);
|
|
TgSolFr_last(*ltt_next_old_solution_ptr) = TgSolFr_last(new_solution);
|
|
FREE_TG_SOLUTION_FRAME(new_solution);
|
|
} else {
|
|
TgSolFr_ltt(new_solution) = ltt;
|
|
TgSolFr_ltt_next(new_solution) = *ltt_next_old_solution_ptr;
|
|
TgSolFr_next(new_solution) = NULL;
|
|
*ltt_next_old_solution_ptr = new_solution;
|
|
}
|
|
} else {
|
|
TgSolFr_ltt(new_solution) = ltt;
|
|
TgSolFr_ltt_next(new_solution) = *old_solution_ptr;
|
|
TgSolFr_next(new_solution) = TgSolFr_next(*old_solution_ptr);
|
|
*old_solution_ptr = new_solution;
|
|
}
|
|
} else {
|
|
TgSolFr_ltt(new_solution) = ltt;
|
|
TgSolFr_ltt_next(new_solution) = NULL;
|
|
TgSolFr_next(new_solution) = *old_solution_ptr;
|
|
*old_solution_ptr = new_solution;
|
|
}
|
|
old_solution_ptr = & TgSolFr_next(*old_solution_ptr);
|
|
new_solution = next_new_solution;
|
|
}
|
|
return new_solution;
|
|
}
|
|
|
|
|
|
static inline
|
|
void CUT_validate_tg_answers(tg_sol_fr_ptr valid_solutions) {
|
|
tg_ans_fr_ptr valid_answers, free_answer;
|
|
tg_sol_fr_ptr ltt_valid_solutions, free_solution;
|
|
ans_node_ptr first_answer, last_answer, ans_node;
|
|
sg_fr_ptr sg_fr;
|
|
int slots;
|
|
|
|
while (valid_solutions) {
|
|
first_answer = last_answer = NULL;
|
|
#ifdef DETERMINISTIC_TABLING
|
|
if (IS_DET_GEN_CP(TgSolFr_gen_cp(valid_solutions)))
|
|
sg_fr = DET_GEN_CP(TgSolFr_gen_cp(valid_solutions))->cp_sg_fr;
|
|
else
|
|
#endif /* DETERMINISTIC_TABLING */
|
|
sg_fr = GEN_CP(TgSolFr_gen_cp(valid_solutions))->cp_sg_fr;
|
|
ltt_valid_solutions = valid_solutions;
|
|
valid_solutions = TgSolFr_next(valid_solutions);
|
|
do {
|
|
valid_answers = TgSolFr_first(ltt_valid_solutions);
|
|
do {
|
|
slots = TgAnsFr_free_slot(valid_answers);
|
|
do {
|
|
ans_node = TgAnsFr_answer(valid_answers, --slots);
|
|
#if defined(TABLE_LOCK_AT_ENTRY_LEVEL)
|
|
LOCK(SgFr_lock(sg_fr));
|
|
#elif defined(TABLE_LOCK_AT_NODE_LEVEL)
|
|
LOCK(TrNode_lock(ans_node));
|
|
#elif defined(TABLE_LOCK_AT_WRITE_LEVEL)
|
|
LOCK_TABLE(ans_node);
|
|
#endif /* TABLE_LOCK_LEVEL */
|
|
if (! IS_ANSWER_LEAF_NODE(ans_node)) {
|
|
TAG_AS_ANSWER_LEAF_NODE(ans_node);
|
|
if (first_answer == NULL)
|
|
first_answer = ans_node;
|
|
else
|
|
TrNode_child(last_answer) = ans_node;
|
|
last_answer = ans_node;
|
|
}
|
|
#if defined(TABLE_LOCK_AT_ENTRY_LEVEL)
|
|
UNLOCK(SgFr_lock(sg_fr));
|
|
#elif defined(TABLE_LOCK_AT_NODE_LEVEL)
|
|
UNLOCK(TrNode_lock(ans_node));
|
|
#elif defined(TABLE_LOCK_AT_WRITE_LEVEL)
|
|
UNLOCK_TABLE(ans_node);
|
|
#endif /* TABLE_LOCK_LEVEL */
|
|
} while (slots);
|
|
free_answer = valid_answers;
|
|
valid_answers = TgAnsFr_next(valid_answers);
|
|
FREE_TG_ANSWER_FRAME(free_answer);
|
|
} while (valid_answers);
|
|
free_solution = ltt_valid_solutions;
|
|
ltt_valid_solutions = TgSolFr_ltt_next(ltt_valid_solutions);
|
|
FREE_TG_SOLUTION_FRAME(free_solution);
|
|
} while (ltt_valid_solutions);
|
|
if (first_answer) {
|
|
LOCK(SgFr_lock(sg_fr));
|
|
if (SgFr_first_answer(sg_fr) == NULL) {
|
|
SgFr_first_answer(sg_fr) = first_answer;
|
|
} else {
|
|
TrNode_child(SgFr_last_answer(sg_fr)) = first_answer;
|
|
}
|
|
SgFr_last_answer(sg_fr) = last_answer;
|
|
UNLOCK(SgFr_lock(sg_fr));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void CUT_join_tg_solutions(tg_sol_fr_ptr *old_solution_ptr, tg_sol_fr_ptr new_solution) {
|
|
tg_sol_fr_ptr next_old_solution, next_new_solution;
|
|
choiceptr gen_cp;
|
|
|
|
do {
|
|
gen_cp = TgSolFr_gen_cp(new_solution);
|
|
while (*old_solution_ptr && YOUNGER_CP(gen_cp, TgSolFr_gen_cp(*old_solution_ptr))) {
|
|
old_solution_ptr = & TgSolFr_next(*old_solution_ptr);
|
|
}
|
|
if (*old_solution_ptr) {
|
|
next_old_solution = *old_solution_ptr;
|
|
*old_solution_ptr = new_solution;
|
|
CUT_join_solution_frame_tg_answers(new_solution);
|
|
if (gen_cp == TgSolFr_gen_cp(next_old_solution)) {
|
|
tg_sol_fr_ptr free_solution;
|
|
TgAnsFr_next(TgSolFr_last(new_solution)) = TgSolFr_first(next_old_solution);
|
|
TgSolFr_last(new_solution) = TgSolFr_last(next_old_solution);
|
|
free_solution = next_old_solution;
|
|
next_old_solution = TgSolFr_next(next_old_solution);
|
|
FREE_TG_SOLUTION_FRAME(free_solution);
|
|
if (! next_old_solution) {
|
|
if ((next_new_solution = TgSolFr_next(new_solution))) {
|
|
CUT_join_solution_frames_tg_answers(next_new_solution);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
gen_cp = TgSolFr_gen_cp(next_old_solution);
|
|
next_new_solution = TgSolFr_next(new_solution);
|
|
while (next_new_solution && YOUNGER_CP(gen_cp, TgSolFr_gen_cp(next_new_solution))) {
|
|
new_solution = next_new_solution;
|
|
next_new_solution = TgSolFr_next(new_solution);
|
|
CUT_join_solution_frame_tg_answers(new_solution);
|
|
}
|
|
old_solution_ptr = & TgSolFr_next(new_solution);
|
|
TgSolFr_next(new_solution) = next_old_solution;
|
|
new_solution = next_new_solution;
|
|
} else {
|
|
*old_solution_ptr = new_solution;
|
|
CUT_join_solution_frames_tg_answers(new_solution);
|
|
return;
|
|
}
|
|
} while (new_solution);
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void CUT_join_solution_frame_tg_answers(tg_sol_fr_ptr join_solution) {
|
|
tg_sol_fr_ptr next_solution;
|
|
|
|
while ((next_solution = TgSolFr_ltt_next(join_solution))) {
|
|
TgAnsFr_next(TgSolFr_last(join_solution)) = TgSolFr_first(next_solution);
|
|
TgSolFr_last(join_solution) = TgSolFr_last(next_solution);
|
|
TgSolFr_ltt_next(join_solution) = TgSolFr_ltt_next(next_solution);
|
|
FREE_TG_SOLUTION_FRAME(next_solution);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void CUT_join_solution_frames_tg_answers(tg_sol_fr_ptr join_solution) {
|
|
do {
|
|
CUT_join_solution_frame_tg_answers(join_solution);
|
|
join_solution = TgSolFr_next(join_solution);
|
|
} while (join_solution);
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void CUT_free_tg_solution_frame(tg_sol_fr_ptr solution) {
|
|
tg_ans_fr_ptr current_answer, next_answer;
|
|
|
|
current_answer = TgSolFr_first(solution);
|
|
do {
|
|
next_answer = TgAnsFr_next(current_answer);
|
|
FREE_TG_ANSWER_FRAME(current_answer);
|
|
current_answer = next_answer;
|
|
} while (current_answer);
|
|
FREE_TG_SOLUTION_FRAME(solution);
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
void CUT_free_tg_solution_frames(tg_sol_fr_ptr current_solution) {
|
|
tg_sol_fr_ptr ltt_solution, next_solution;
|
|
|
|
while (current_solution) {
|
|
ltt_solution = TgSolFr_ltt_next(current_solution);
|
|
while (ltt_solution) {
|
|
next_solution = TgSolFr_ltt_next(ltt_solution);
|
|
CUT_free_tg_solution_frame(ltt_solution);
|
|
ltt_solution = next_solution;
|
|
}
|
|
next_solution = TgSolFr_next(current_solution);
|
|
CUT_free_tg_solution_frame(current_solution);
|
|
current_solution = next_solution;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static inline
|
|
tg_sol_fr_ptr CUT_prune_tg_solution_frames(tg_sol_fr_ptr solutions, int ltt) {
|
|
tg_sol_fr_ptr ltt_next_solution, return_solution;
|
|
|
|
if (! solutions) return NULL;
|
|
return_solution = CUT_prune_tg_solution_frames(TgSolFr_next(solutions), ltt);
|
|
while (solutions && ltt > TgSolFr_ltt(solutions)) {
|
|
ltt_next_solution = TgSolFr_ltt_next(solutions);
|
|
CUT_free_tg_solution_frame(solutions);
|
|
solutions = ltt_next_solution;
|
|
}
|
|
if (solutions) {
|
|
TgSolFr_next(solutions) = return_solution;
|
|
return solutions;
|
|
} else {
|
|
return return_solution;
|
|
}
|
|
}
|
|
#endif /* TABLING_INNER_CUTS */
|