/* File: slgdelay.c ** Author(s): Kostis Sagonas, Baoqiu Cui ** Contact: xsb-contact@cs.sunysb.edu ** ** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1998 ** Copyright (C) ECRC, Germany, 1990 ** ** XSB is free software; you can redistribute it and/or modify it under the ** terms of the GNU Library General Public License as published by the Free ** Software Foundation; either version 2 of the License, or (at your option) ** any later version. ** ** XSB is distributed in the hope that it will be useful, but WITHOUT ANY ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ** FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for ** more details. ** ** You should have received a copy of the GNU Library General Public License ** along with XSB; if not, write to the Free Software Foundation, ** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ** ** $Id: slgdelay.c,v 1.37 2002/05/31 15:09:03 lfcastro Exp $ ** */ #include "xsb_config.h" #include "xsb_debug.h" #include #include /* special debug includes */ #include "debugs/debug_delay.h" #include "auxlry.h" #include "cell_xsb.h" #include "psc_xsb.h" #include "register.h" #include "trie_internals.h" #include "memory_xsb.h" #include "choice.h" #include "macro_xsb.h" #include "tr_utils.h" #include "inst_xsb.h" #include "error_xsb.h" #include "io_builtins_xsb.h" static void simplify_neg_succeeds(VariantSF); extern void simplify_pos_unsupported(NODEptr); static void simplify_pos_unconditional(NODEptr); /* * Some new global variables ... */ static unsigned long de_block_size = 2048 * sizeof(struct delay_element); static unsigned long dl_block_size = 2048 * sizeof(struct delay_list); static unsigned long pnde_block_size = 2048 * sizeof(struct pos_neg_de_list); static char *current_de_block = NULL; static char *current_dl_block = NULL; static char *current_pnde_block = NULL; static DE released_des = NULL; /* the list of released DEs */ static DL released_dls = NULL; /* the list of released DLs */ static PNDE released_pndes = NULL; /* the list of released PNDEs */ static DE next_free_de = NULL; /* next available free DE space */ static DL next_free_dl = NULL; /* next available free DL space */ static PNDE next_free_pnde = NULL; /* next available free PNDE space */ static DE current_de_block_top = NULL; /* the top of current DE block */ static DL current_dl_block_top = NULL; /* the top of current DL block */ static PNDE current_pnde_block_top = NULL; /* the top of current PNDE block */ static char *new_block; /* used in new_entry() */ /* * A macro definition for allocating a new entry of DE, DL, or PNDE. To * release such an entry, use definition release_entry (see below). * * new_entry(NEW_ENTRY, -- pointer to the new entry * RELEASED, -- pointer to the released entries * NEXT_FREE, -- pointer to the next free entry * CURRENT_BLOCK, -- pointer to the current block * CURRENT_BLOCK_TOP, -- pointer to the current block top * NEXT_FUNCTION, -- next function (eg. de_next) * ENTRY_TYPE, -- type of the entry (eg. DE) * BLOCK_SIZE, -- block size (for malloc a new block) * ABORT_MESG) -- xsb_abort mesg when no enough memory */ #define new_entry(NEW_ENTRY, \ RELEASED, \ NEXT_FREE, \ CURRENT_BLOCK, \ CURRENT_BLOCK_TOP, \ NEXT_FUNCTION, \ ENTRY_TYPE, \ BLOCK_SIZE, \ ABORT_MESG) \ if (RELEASED) { \ NEW_ENTRY = RELEASED; \ RELEASED = NEXT_FUNCTION(RELEASED); \ } \ else if (NEXT_FREE < CURRENT_BLOCK_TOP) \ NEW_ENTRY = NEXT_FREE++; \ else { \ if ((new_block = (char *) malloc(BLOCK_SIZE + sizeof(Cell))) == NULL)\ xsb_abort(ABORT_MESG); \ *(char **) new_block = CURRENT_BLOCK; \ CURRENT_BLOCK = new_block; \ NEXT_FREE = (ENTRY_TYPE)(new_block + sizeof(Cell)); \ CURRENT_BLOCK_TOP = (ENTRY_TYPE)(new_block + sizeof(Cell) + BLOCK_SIZE);\ NEW_ENTRY = NEXT_FREE++; \ } #define release_entry(ENTRY_TO_BE_RELEASED, \ RELEASED, \ NEXT_FUNCTION) { \ NEXT_FUNCTION(ENTRY_TO_BE_RELEASED) = RELEASED; \ RELEASED = ENTRY_TO_BE_RELEASED; \ } /* * remove_pnde(PNDE_HEAD, PNDE_ITEM) removes PNDE_ITEM from the * corresponding doubly-linked PNDE list. If PNDE_ITEM is the first one * in the list, resets PNDE_HEAD to point to the next one. * * One principle: Whenever we remove a DE, its PDE (or NDE) must be * removed from the PNDE list *first* using remove_pnde(). */ #define remove_pnde(PNDE_HEAD, PNDE_ITEM) { \ PNDE *pnde_head_ptr; \ PNDE next; \ \ pnde_head_ptr = &(PNDE_HEAD); \ next = pnde_next(PNDE_ITEM); \ if (*pnde_head_ptr == PNDE_ITEM) \ *pnde_head_ptr = next; \ else { \ pnde_next(pnde_prev(PNDE_ITEM)) = next; \ if (next) \ pnde_prev(next) = pnde_prev(PNDE_ITEM); \ } \ release_entry(PNDE_ITEM, released_pndes, pnde_next); \ } /* * The following functions are used for statistics. */ unsigned long allocated_de_space(int * num_blocks) { int size = 0; char *t = current_de_block; *num_blocks = 0; while (t) { (*num_blocks)++; size =+ (de_block_size + sizeof(Cell)); t = *(char **)t; } return size; } static int released_de_num(void) { int i = 0; DE p; p = released_des; while (p != NULL) { i++; p = de_next(p); } return(i); } unsigned long unused_de_space(void) { return (current_de_block_top - next_free_de + released_de_num()) * sizeof(struct delay_element); } unsigned long allocated_dl_space(int * num_blocks) { int size = 0; char *t = current_dl_block; *num_blocks = 0; while (t) { (*num_blocks)++; size =+ (dl_block_size + sizeof(Cell)); t = *(char **)t; } return size; } static int released_dl_num(void) { int i = 0; DL p; p = released_dls; while (p != NULL) { i++; p = dl_next(p); } return(i); } unsigned long unused_dl_space(void) { return (current_dl_block_top - next_free_dl + released_dl_num()) * sizeof(struct delay_list); } /* * Assign one entry for delay_elem in the current DE (Delay Element) * block. A new block will be allocate if necessary. */ static DE intern_delay_element(Cell delay_elem) { DE de; CPtr cptr = (CPtr) cs_val(delay_elem); /* * All the following information about delay_elem is set in * delay_negatively() or delay_positively(). Note that cell(cptr) is * the delay_psc ('DL'). */ VariantSF subgoal; NODEptr ans_subst; CPtr ret_n = 0; int arity; Cell tmp_cell; tmp_cell = cell(cptr + 1); subgoal = (VariantSF) addr_val(tmp_cell); tmp_cell = cell(cptr + 2); ans_subst = (NODEptr) addr_val(tmp_cell); tmp_cell = cell(cptr + 3); /* * cell(cptr + 3) can be one of the following: * 1. integer 0 (NEG_DELAY), for a negative DE; * 2. string "ret", for a positive DE with arity 0; * 3. constr ret/n, for a positive DE with arity >=1. */ if (isinteger(tmp_cell) || isstring(tmp_cell)) arity = 0; else { ret_n = (CPtr) cs_val(tmp_cell); arity = get_arity((Psc) get_str_psc(cell(cptr + 3))); } #ifdef DEBUG_DELAYVAR xsb_dbgmsg((LOG_DEBUG,">>>> ")); dbg_print_delay_list(LOG_DEBUG,stddbg, delayreg); xsb_dbgmsg((LOG_DEBUG, "\n")); xsb_dbgmsg((LOG_DEBUG, ">>>> (Intern ONE de) arity of answer subsf = %d\n", arity)); #endif if (!was_simplifiable(subgoal, ans_subst)) { new_entry(de, released_des, next_free_de, current_de_block, current_de_block_top, de_next, DE, de_block_size, "Not enough memory to expand DE space"); de_subgoal(de) = subgoal; de_ans_subst(de) = ans_subst; /* Leaf of the answer (substitution) trie */ #ifdef DEBUG_DELAYVAR de_subs_fact(de) = NULL; #ifndef IGNORE_DELAYVAR if (arity != 0) { de_subs_fact_leaf(de) = delay_chk_insert(arity, ret_n + 1, (CPtr *) &de_subs_fact(de)); } #endif /* IGNORE_DELAYVAR */ #else #ifndef IGNORE_DELAYVAR if (arity != 0) { CPtr hook = NULL; de_subs_fact_leaf(de) = delay_chk_insert(arity, ret_n + 1, &hook); } #endif /* IGNORE_DELAYVAR */ #endif return de; } else return NULL; } /* * Construct a delay list according to dlist. Assign an entry in the * current DL block for it. A new DL block will be allocated if * necessary. */ static DL intern_delay_list(CPtr dlist) /* assumes that dlist != NULL */ { DE head = NULL, de; DL dl = NULL; while (islist(dlist)) { dlist = clref_val(dlist); if ((de = intern_delay_element(cell(dlist))) != NULL) { de_next(de) = head; head = de; } dlist = (CPtr) cell(dlist+1); } if (head) { new_entry(dl, released_dls, next_free_dl, current_dl_block, current_dl_block_top, dl_next, DL, dl_block_size, "Not enough memory to expand DL space"); dl_de_list(dl) = head; dl_asl(dl) = NULL; return dl; } else return NULL; } /* * For each delay element de in delay list dl, do one of the following * things: * * 1) (If de is a negative DE) Add a NDE `pnde' to the nde_list of de's * subgoal frame. Point de_pnde(de) to `pnde', and point * pnde_dl(pnde) to dl, pnde_de(pnde) to de. * * 2) (If de is a positive DE) Add a PDE `pnde' to the pdes of the * Delay Info node of de's answer substitution leaf. Point * de_pnde(de) to `pnde', and point pnde_dl(pnde) to dl, pnde_de(pnde) * to de. */ static void record_de_usage(DL dl) { DE de; PNDE pnde, current_first; NODEptr as_leaf; #ifdef DEBUG_DELAYVAR PNDE tmp; #endif de = dl_de_list(dl); while (de) { new_entry(pnde, released_pndes, next_free_pnde, current_pnde_block, current_pnde_block_top, pnde_next, PNDE, pnde_block_size, "Not enough memory to expand PNDE space"); pnde_dl(pnde) = dl; pnde_de(pnde) = de; pnde_prev(pnde) = NULL; if ((as_leaf = de_ans_subst(de)) == NULL) { /* a negative DE */ current_first = subg_nde_list(de_subgoal(de)); #ifdef DEBUG_DELAYVAR tmp = current_first; while (tmp) { if (pnde_de(tmp) == de) { printf(">>>> ERROR: tmp = %p, tmp->de = %p\n", tmp, pnde_de(tmp)); } tmp = pnde_next(tmp); } #endif pnde_next(pnde) = current_first; if (current_first) pnde_prev(current_first) = pnde; subg_nde_list(de_subgoal(de)) = pnde; } else { /* a positive DE */ current_first = asi_pdes(Delay(as_leaf)); pnde_next(pnde) = current_first; if (current_first) pnde_prev(current_first) = pnde; asi_pdes(Delay(as_leaf)) = pnde; } de_pnde(de) = pnde; /* record */ de = de_next(de); } } /* * Function do_delay_stuff() is called in the SLG instruction * `new_answer_dealloc', when an answer (new or not) is returned for the * current call. Here, `as_leaf' is the leaf node of the answer trie * (TrieRetPtr, the return value of variant_answer_search), `subgoal' is * the subgoal frame of the current call, and `sf_exists' tells whether * this answer is new or not. * * At this time, `delayreg' is the delay register of the _current_ call. * If it is not NULL, then it means this answer has some delay elements * and is a conditional one. (Remember, all the delay elements under * this current call have been processed by delay_positively() or * delay_negatively(), and `delayreg' has been updated and pointed to the * delay list. All the information about the delay list is still saved * on the heap.) * * Function intern_delay_list() will be called to save the delay list * information in the Delay Info node of current call's answer leaf. It * will call intern_delay_element(), which will call delay_chk_insert(). * A delay trie is created by delay_chk_insert() for the corresponding * delay element. * * When the delay trie has been created, and a pointer in the delay * element (saved in the answer trie) has been set, we can say the * conditional answer is now tabled. */ void do_delay_stuff(NODEptr as_leaf, VariantSF subgoal, xsbBool sf_exists) { ASI asi; DL dl = NULL; #ifdef DEBUG_DELAYVAR xsb_dbgmsg((LOG_DEBUG, ">>>> Start do_delay_stuff ...\n")); xsb_dbgmsg((LOG_DEBUG, ">>>> The delay list for this subgoal itself is:\n")); xsb_dbgmsg((LOG_DEBUG, ">>>> ")); dbg_print_delay_list(LOG_DEBUG,stddbg, delayreg); xsb_dbgmsg((LOG_DEBUG, "\n")); #endif if (delayreg && (!sf_exists || is_conditional_answer(as_leaf))) { if ((dl = intern_delay_list(delayreg)) != NULL) { mark_conditional_answer(as_leaf, subgoal, dl); record_de_usage(dl); } } /* * Check for the derivation of an unconditional answer. */ if (sf_exists && is_conditional_answer(as_leaf) && (!delayreg || !dl)) { /* * Initiate positive simplification in places where this answer * substitution has already been returned. */ simplify_pos_unconditional(as_leaf); } if (is_unconditional_answer(as_leaf) && subg_nde_list(subgoal)) { simplify_neg_succeeds(subgoal); } } /*----------------------------------------------------------------------*/ xsbBool answer_is_junk(CPtr dlist) /* assumes that dlist != NULL */ { CPtr cptr; VariantSF subgoal; NODEptr ans_subst; Cell tmp_cell; while (islist(dlist)) { dlist = clref_val(dlist); cptr = (CPtr) cs_val(cell(dlist)); tmp_cell = cell(cptr + 1); subgoal = (VariantSF) addr_val(tmp_cell); tmp_cell = cell(cptr + 2); ans_subst = (NODEptr) addr_val(tmp_cell); if (is_failing_delay_element(subgoal,ans_subst)) { return TRUE; } dlist = (CPtr) cell(dlist+1); } return FALSE; } /* * Function remove_de_from_dl(de, dl) removes de from dl when de is * positive and succeeds, or negative and fails. It is used in * simplify_pos_unconditional() and simplify_neg_fails(). */ static xsbBool remove_de_from_dl(DE de, DL dl) { DE current = dl_de_list(dl); DE prev_de = NULL; #ifdef DEBUG_DELAYVAR fprintf(stddbg, ">>>> start remove_de_from_dl()\n"); #endif while (current != de) { prev_de = current; current = de_next(current); } if (prev_de == NULL) /* to remove the first DE */ dl_de_list(dl) = de_next(current); else de_next(prev_de) = de_next(current); release_entry(current, released_des, de_next); return (NULL != dl_de_list(dl)); } /* * Function remove_dl_from_dl_list(dl, asi) removes dl from the DL list * which is pointed by asi. Called when a DE in dl is negative and * succeeds, or positive and unsupported (in functions * simplify_neg_succeeds() and simplify_pos_unsupported()). */ static xsbBool remove_dl_from_dl_list(DL dl, ASI asi) { DL current = asi_dl_list(asi); DL prev_dl = NULL; #ifdef DEBUG_DELAYVAR fprintf(stddbg, ">>>> start remove_dl_from_dl_list()\n"); #endif while (current != dl) { prev_dl = current; current = dl_next(current); } if (prev_dl == NULL) /* to remove the first DL */ asi_dl_list(asi) = dl_next(current); else dl_next(prev_dl) = dl_next(current); release_entry(current, released_dls, dl_next); return (NULL != asi_dl_list(asi)); } /* * When a DL becomes empty (after remove_de_from_dl()), the answer * substitution which uses this DL becomes unconditional. Further * simplification operations go on ... */ static void handle_empty_dl_creation(DL dl) { NODEptr as_leaf = dl_asl(dl); ASI asi = Delay(as_leaf); VariantSF subgoal; #ifdef DEBUG_DELAYVAR fprintf(stddbg, ">>>> start handle_empty_dl_creation()\n"); #endif /* * Only when `as_leaf' is still a conditional answer can we do * remove_dl_from_dl_list(), simplify_pos_unconditional(), and * simplify_neg_succeeds() here. * * If `as_leaf' is already marked UNCONDITIONAL (by * unmark_conditional_answer(as_leaf) in simplify_pos_unconditional()), * that means this is the second time when `as_leaf' becomes * unconditional. So we don't need do anything. All the DLs have been * released in the first time. */ if (is_conditional_answer(as_leaf)) { /* if it is still conditional */ remove_dl_from_dl_list(dl, asi); subgoal = asi_subgoal(Delay(as_leaf)); #ifdef DEBUG_DELAYVAR xsb_dbgmsg((LOG_DEBUG, ">>>> the subgoal is:")); dbg_print_subgoal(LOG_DEBUG,stddbg, subgoal); xsb_dbgmsg((LOG_DEBUG, "\n")); #endif /* * simplify_pos_unconditional(as_leaf) will release all other DLs for * as_leaf, and mark as_leaf as UNCONDITIONAL. */ simplify_pos_unconditional(as_leaf); /*-- perform early completion if necessary; please preserve invariants --*/ if (!is_completed(subgoal) && most_general_answer(as_leaf)) { perform_early_completion(subgoal, subg_cp_ptr(subgoal)); subg_compl_susp_ptr(subgoal) = NULL; } simplify_neg_succeeds(subgoal); } } /* * Run further simplifications when an answer substitution leaf, * as_leaf, has no supported conditional answers. This happens when * all DLs of as_leaf are removed (by remove_dl_from_dl_list) */ static void handle_unsupported_answer_subst(NODEptr as_leaf) { ASI unsup_asi = Delay(as_leaf); VariantSF unsup_subgoal = asi_subgoal(unsup_asi); #ifdef DEBUG_DELAYVAR fprintf(stddbg, ">>>> start handle_unsupported_answer_subst()\n"); #endif delete_branch(as_leaf, &subg_ans_root_ptr(unsup_subgoal)); simplify_pos_unsupported(as_leaf); if (is_completed(unsup_subgoal)) { if (subgoal_fails(unsup_subgoal)) { simplify_neg_fails(unsup_subgoal); } } free(unsup_asi); } /* * To release all the DLs (and their DEs) in the DelayInfo node `asi'. */ void release_all_dls(ASI asi) { ASI de_asi; DE de, tmp_de; DL dl, tmp_dl; dl = asi_dl_list(asi); while (dl) { tmp_dl = dl_next(dl); de = dl_de_list(dl); while (de) { tmp_de = de_next(de); if (de_ans_subst(de) == NULL) { /* is NDE */ remove_pnde(subg_nde_list(de_subgoal(de)), de_pnde(de)); } else { de_asi = Delay(de_ans_subst(de)); remove_pnde(asi_pdes(de_asi), de_pnde(de)); } release_entry(de, released_des, de_next); de = tmp_de; /* next DE */ } /* while (de) */ release_entry(dl, released_dls, dl_next); dl = tmp_dl; /* next DL */ } } /* * When the answers substitution gets an unconditional answer, remove * the positive delay literals of this answer substitution from the * delay lists that contain them. */ static void simplify_pos_unconditional(NODEptr as_leaf) { ASI asi = Delay(as_leaf); PNDE pde; DE de; DL dl; #ifdef DEBUG_DELAYVAR fprintf(stddbg, ">>>> start simplify_pos_unconditional()\n"); #endif release_all_dls(asi); unmark_conditional_answer(as_leaf); while ((pde = asi_pdes(asi))) { de = pnde_de(pde); dl = pnde_dl(pde); remove_pnde(asi_pdes(asi), pde); if (!remove_de_from_dl(de, dl)) handle_empty_dl_creation(dl); } /* * Now this DelayInfo `asi' does not contain any useful info, so we can * free it, and really mark `as_leaf' as an unconditional answer. */ Child(as_leaf) = NULL; free(asi); } /* * When the subgoal fails (is completed without any answers), remove * the negative delay literals of this subgoal from the delay lists * that contain them. */ void simplify_neg_fails(VariantSF subgoal) { PNDE nde; DE de; DL dl; #ifdef DEBUG_DELAYVAR xsb_dbgmsg((LOG_DEBUG, ">>>> start simplify_neg_fails()\n")); xsb_dbgmsg((LOG_DEBUG, ">>>> the subgoal is: ")); dbg_print_subgoal(LOG_DEBUG,stddbg, subgoal); xsb_dbgmsg((LOG_DEBUG, "\n")); #endif while ((nde = subg_nde_list(subgoal))) { de = pnde_de(nde); dl = pnde_dl(nde); remove_pnde(subg_nde_list(subgoal), nde); if (!remove_de_from_dl(de, dl)) handle_empty_dl_creation(dl); } #ifdef DEBUG_DELAYVAR fprintf(stddbg, ">>>> end simplify_neg_fails()\n"); #endif } /* * On occasion that the subgoal succeeds (gets an unconditional * answer that is identical to the subgoal), it deletes all delay * lists that contain a negative delay element with that subgoal. * * Before remove_dl_from_dl_list(), all the DEs in the DL to be * removed have to be released, and each P(N)DE which points to a DE * in the DL has also to be released. */ static void simplify_neg_succeeds(VariantSF subgoal) { PNDE nde; DL dl; DE de, tmp_de; ASI used_asi, de_asi; NODEptr used_as_leaf; #ifdef DEBUG_DELAYVAR fprintf(stddbg, ">>>> start simplify_neg_succeeds()\n"); #endif while ((nde = subg_nde_list(subgoal))) { dl = pnde_dl(nde); /* dl: to be removed */ used_as_leaf = dl_asl(dl); if (IsValidNode(used_as_leaf) && (used_asi = Delay(used_as_leaf)) != NULL) { de = dl_de_list(dl); /* to release all DEs in dl */ while (de) { tmp_de = de_next(de); if (de_ans_subst(de) == NULL) { /* is NDE */ remove_pnde(subg_nde_list(de_subgoal(de)), de_pnde(de)); } else { de_asi = Delay(de_ans_subst(de)); remove_pnde(asi_pdes(de_asi), de_pnde(de)); } #ifdef DEBUG_DELAYVAR fprintf(stddbg, ">>>> release DE (in simplify_neg_succeeds)\n"); #endif release_entry(de, released_des, de_next); de = tmp_de; /* next DE */ } /* while */ if (!remove_dl_from_dl_list(dl, used_asi)) { handle_unsupported_answer_subst(used_as_leaf); } } /* if */ } /* while */ } /* * On occasion that an AnswerSubstitution at `as_leaf' looses all its * conditional answers (all its DLs have been removed), * simplify_pos_unsupported() deletes all delay lists (of other * predicates' conditional answers) that contain a positive delay element * pointing to that AnswerSubstitution. */ void simplify_pos_unsupported(NODEptr as_leaf) { ASI asi = Delay(as_leaf); PNDE pde; DL dl; DE de, tmp_de; ASI used_asi, de_asi; NODEptr used_as_leaf; #ifdef DEBUG_DELAYVAR fprintf(stddbg, ">>>> start simplify_pos_unsupported()\n"); #endif while ((pde = asi_pdes(asi))) { dl = pnde_dl(pde); /* dl: to be removed */ used_as_leaf = dl_asl(dl); if (IsValidNode(used_as_leaf) && (used_asi = Delay(used_as_leaf)) != NULL) { de = dl_de_list(dl); /* to release all DEs in dl */ while (de) { tmp_de = de_next(de); if (de_ans_subst(de) == NULL) { /* is NDE */ remove_pnde(subg_nde_list(de_subgoal(de)), de_pnde(de)); } else { /* is PDE */ de_asi = Delay(de_ans_subst(de)); remove_pnde(asi_pdes(de_asi), de_pnde(de)); } #ifdef DEBUG_DELAYVAR fprintf(stddbg, ">>>> release DE (in simplify_pos_unsupported)"); #endif release_entry(de, released_des, de_next); de = tmp_de; /* next DE */ } /* while */ if (!remove_dl_from_dl_list(dl, used_asi)) { handle_unsupported_answer_subst(used_as_leaf); } } /* if */ } /* while */ } void abolish_wfs_space(void) { char *last_block; #ifndef LOCAL_EVAL extern void abolish_edge_space(); #endif /* clear DE blocks */ while (current_de_block) { last_block = *(char **) current_de_block; free(current_de_block); current_de_block = last_block; } /* clear DL blocks */ while (current_dl_block) { last_block = *(char **) current_dl_block; free(current_dl_block); current_dl_block = last_block; } /* clear PNDE blocks */ while (current_pnde_block) { last_block = *(char **) current_pnde_block; free(current_pnde_block); current_pnde_block = last_block; } /* reset some pointers */ released_des = NULL; released_dls = NULL; released_pndes = NULL; next_free_de = NULL; next_free_dl = NULL; next_free_pnde = NULL; current_de_block_top = NULL; current_dl_block_top = NULL; current_pnde_block_top = NULL; #ifndef LOCAL_EVAL abolish_edge_space(); #endif } /* * Two functions added for builtin force_truth_value/2. */ void force_answer_true(NODEptr as_leaf) { VariantSF subgoal; if (is_conditional_answer(as_leaf)) { subgoal = asi_subgoal(Delay(as_leaf)); simplify_pos_unconditional(as_leaf); simplify_neg_succeeds(subgoal); } } void force_answer_false(NODEptr as_leaf) { ASI asi = Delay(as_leaf); VariantSF subgoal; if (is_conditional_answer(as_leaf)) { subgoal = asi_subgoal(asi); release_all_dls(asi); delete_branch(as_leaf, &subg_ans_root_ptr(subgoal)); simplify_pos_unsupported(as_leaf); mark_subgoal_failed(subgoal); simplify_neg_fails(subgoal); } } /*---------------------- end of file slgdelay.c ------------------------*/