Unable to retract/retractall using c interface

I’m using: SWI-Prolog version 8.0.2
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609

I want the code to:
retract asserted facts.
i’ve tested predicates defined with both the dynamic and thread_local definitions ( same results )

i’ve tested both retractall on a compound built with PL_put_variable (i.e. retractall(functor(,,…)
-> next_solution returns PL_S_TRUE but does not retract ( subsequent “selection” of the data returns data ).

i’ve tried implementing my own retractall ( i.e. read all values/solutions and explicitly retract each one )
but next_solution on the retract returns PS_S_FALSE. ( and does not retract the data ).

code examples :

using retractall :
const predicate_t RetractCMD = PL_predicate(“retractall”, 1, “database”);
const functor_t Targetfunctor = PL_new_functor(PL_new_atom(“target”), 4);
term_t EmptyTargetParameters = PL_new_term_refs(4);
if ( PL_put_variable(EmptyTargetParameters) != PL_S_TRUE
|| PL_put_variable(EmptyTargetParameters+1) != PL_S_TRUE
|| PL_put_variable(EmptyTargetParameters+2) != PL_S_TRUE
|| PL_put_variable(EmptyTargetParameters+3) != PL_S_TRUE)
{ exit }

term_t TargetCompoundToRetract = PL_new_term_ref();
if (PL_cons_functor_v(TargetCompoundToRetract,Targetfunctor,EmptyTargetParameters) != PL_S_TRUE)
{ exit }

const qid_t RetractTargetsQID = PL_open_query(NULL, PL_Q_NODEBUG ,RetractCMD,TargetCompoundToRetract);
if (RetractTargetsQID == 0)
{ exit }

QueryRc = PL_next_solution(RetractTargetsQID);
if (QueryRc != PL_S_TRUE)
{ exit }

using retract :
const predicate_t PredToDelete = PL_predicate(“target”, 4, “database”);
term_t DataToDelete = PL_new_term_refs(4);
const functor_t functorToDelete = PL_new_functor(PL_new_atom(“target”), 4);
const predicate_t RetractCMD = PL_predicate(“retract”, 1, “database”);

const qid_t GetDataQID = PL_open_query(NULL,PL_Q_NODEBUG,PredToDelete,DataToDelete);
if (GetDataQID == 0)
{ exit }

int QueryRc = PL_next_solution(GetDataQID);
while (QueryRc != PL_S_FALSE)
{
     // construct compound argument for retract command
    term_t CompoundToRetract = PL_new_term_ref();
    if (PL_cons_functor_v(CompoundToRetract,functorToDelete,DataToDelete) != PL_S_TRUE)
    {     exit   }

  const qid_t  RetractQID   = 
  PL_open_query(NULL,PL_Q_NODEBUG,RetractCMD,CompoundToRetract);
    if (RetractQID == 0)
    {    exit        }   

   //
    QueryRc = PL_next_solution(RetractQID);
    if (QueryRc != PL_S_TRUE)
    {       exit      }

}

Without looking through all details, I think the misconception is with PL_predicate(“retractall”, 1, “database”). This doesn’t get retractall/1 for the module database, but the meta predicate retractall/1 as it is visible in database, which is the same as in system or any other module.

Next, you call it without module context and this means you’re probably referring to the system module. The debugger should be able to tell you.

You should either create a term database:target(_,_,_,_) or pass the module database as first argument to PL_open_query().

P.s. PL_S_TRUE and friends are for the extended return status of PL_next_solution() only. All other functions return 1 or 0, available as TRUE and FALSE`.

And as a general remark. keep the stuff you call from C(++) as simple as possible. For example, define in database a predicate cleanup/0. That also fixes the module stuff:

cleanup :-
    retractall(target(_,_,_,_)).
1 Like

thank you Jan for trying to help.

I was not aware of the “modules” element.
(as far as i can tell its not the cause (all my assert/retract statements use the “database” module) )

I’ve done some debugging.
it looks like some sort of bug in the assert of compound predicates.

I have more then 1 predicate i need to assert/retract.
my code works for one predicate with only 1 parameter.

but once i add the assert(target(int,int,int,int)) it messes things up , it even messed up the “state” of the other predicate ( the one that has only 1 int parameter).

i’ve debugged it to the point that i can say that the following cmd is the one that causes the problem :
if (!PL_put_integer(TargetToAssert+3,int))
i.e. setting the value in the last element of the array ( used later in PL_cons_functor_v).

any ideas?

omer.

btw,

i’ve tried the “cleanup” workaround.
but it did not work.

i’ve defined :
cleanup(NewMaxCostFound):-
retractall(target(,,,)),
retractall(maxcostfound(_)),
assert(maxcostfound(NewMaxCostFound)).

count_number_of_asserted_targets(NumberOfTargets):-
findall(TargetID,target(TargetID,,,_),Bag),
length(Bag,NumberOfTargets).

a new cpp method that calls cleanup .
then asserts one “target”
then calls count_number_of_asserted_targets.

on its first execution (nothing to retract) i get the correct number of targets (=1)
second execution of the same code , i get number of asserted targets = 0.

?
Omer

Nothing is impossible, but I consider that highly unlikely. Most likely you are misusing the C++ API somehow. As there is no complete code it is hard to say where though. If Prolog has access to the console you can insert a trace/0 call to see what is called. Misuse of the C++ API can easily result in data corruption and crashes though. One trick is to call garbage_collect/0, as this normally either crashes or make slightly wrong data completely wrong.

hello Jan,

would you like me to post the complete code here?

thanks,
Omer

Preferably something small, but complete so we can compile and run it. If it can’t be small (but it seems it can), put it somewhere else and point us at the things we should look at.

hello Jan,

here is a slightly watered down version of the code

void InitQuery()
{

term_t MaxCostFoundTerm = PL_new_term_ref();
if (!PL_put_integer(MaxCostFoundTerm,MaxCostFound))
{
    return;
}

const predicate_t   InitWingCMD      = PL_predicate("initialize_wing_path_query",1,"database");
const qid_t         InitWingPathQID  = PL_open_query(NULL, PL_Q_NORMAL,InitWingCMD,MaxCostFoundTerm);
if (InitWingPathQID == 0)
{
    return;
}

QueryRc = PL_next_solution(InitWingPathQID);
//std::cout << "qrc = " << QueryRc << std::endl;
if (QueryRc != TRUE)
{
    return;
}

if (!PL_close_query(InitWingPathQID))
{
    return;
}

	// assert target //

//
if (!PL_put_integer(TargetToAssert,1))
{
    return;
}
if (!PL_put_integer(TargetToAssert+1,2))
{
    return;
}
if (!PL_put_integer(TargetToAssert+2,3))
{
    return;
}

if (!PL_put_integer(TargetToAssert+3,4))
{
    return;
}
 
//
const functor_t Targetfunctor = PL_new_functor(PL_new_atom("target"), 4);
const predicate_t   AssertCMD1  = PL_predicate("assert", 1, "database");
term_t TargetCompoundToAssert = PL_new_term_ref();
if (!PL_cons_functor_v(TargetCompoundToAssert,Targetfunctor,TargetToAssert))
{
    return;
}
 
//
const qid_t  AssertTargetQID1  = PL_open_query(NULL, PL_Q_NORMAL,AssertCMD1,TargetCompoundToAssert);
if (AssertTargetQID1 == 0)
{
    return;
}

QueryRc = PL_next_solution(AssertTargetQID1);
if (QueryRc != TRUE)
{
    return;
}

if (!PL_close_query(AssertTargetQID1))
{
    return;
}

}

void CheckInitQuery()
{
std::cout << "check assertion of max cost found " << std::endl;

    // check assertion of max cost found //
          term_t        Result      = PL_new_term_ref();
    const predicate_t   PredToRun   = PL_predicate("maxcostfound", 1, "database");
    const qid_t         QID         = PL_open_query(NULL,PL_Q_NODEBUG | PL_Q_EXT_STATUS,PredToRun,Result);
    if (QID == 0)
    {
        return;
    }

    QueryRc = PL_next_solution(QID);
    //std::cout << "qrc = " << QueryRc << std::endl;
    if (QueryRc != PL_S_LAST)
    {
        return;
    }

    // parse the result
    //std::cout << "term type " << PL_term_type(Result) << std::endl;
    if (PL_term_type(Result) != PL_INTEGER)
    {
        return;
    }

    int ReadInt;
    if (PL_get_integer(Result,&ReadInt) != PL_S_TRUE)
    {
        return;
    }
    if (ReadInt != MaxCostFound)
    {
        return;
    }
    std::cout << "max cost found asserted successfully" << std::endl;

    if (!PL_close_query(QID))
    {
        return;
    }


    // check number of asserted targets //
          term_t        NumberOfAssertedTargets = PL_new_term_ref();
    const predicate_t   CountCMD                = PL_predicate("count_number_of_asserted_targets", 1, "database");
    const qid_t         CountQID                = PL_open_query(NULL,PL_Q_NODEBUG,CountCMD,NumberOfAssertedTargets);
    if (CountQID == 0)
    {
          return;
    }

    QueryRc = PL_next_solution(CountQID);
    //std::cout << "qrc = " << QueryRc << std::endl;
    if (QueryRc != TRUE)
    {
        return;
    }

    // parse the result
    if (PL_term_type(NumberOfAssertedTargets) != PL_INTEGER)
    {
        return;
    }

    if (PL_get_integer(NumberOfAssertedTargets,&ReadInt) != PL_S_TRUE)
    {
        return;
    }

    std::cout <<  "number of targets asserted =  "  << ReadInt << std::endl;

    if (!PL_close_query(CountQID))
    {
        return;
    }

}

i’ve already posted the contents of count_number_of_asserted_targets and initialize_wing_path_query.

my prolog src file also contains:
:- thread_local target/4.
:- thread_local maxcostfound/1.

Thanks,
Omer.

So sorry, but it is incomplete. TargetToAssert is declared nor initialized. Same for several other variables. There are no included headers, there is no main() or some other indication how it is loaded and started. The stuff that is there seems to make sense, but essential stuff is missing and if it turns out there is nothing obviously wrong someone who wants to help you will have to complete the code such that it can be compiled and executed.

Please send _complete code and do not ask the list to collect and fill out the blanks.

Ok Jan,
u r correct 100%,

i’ve polished off the watered down version,
and found out it works correctly.

so i’ll keep digging.

thanks again for all the help.
Omer.