Current status of s(CASP)

I’m considering using the s(CASP) pack for rules-based fault diagnosis. However I’m wondering what the current status is - the docs seem kinda sparse, the only comprehensive ones I’ve been able to find are on the SWISH site at https://swish.swi-prolog.org/pldoc/pack/sCASP/ and it looks like the main development is elsewhere? Also, many of the examples don’t seem to work any more?

I’ll be using it internally so it will be fine as long as it will keep working on future SWI versions.

Another question: In some of the examples I see things like this:

#pred wounded_bird(X) :: '@(X) is a wounded bird'.
wounded_bird(john). % john is wounded

but I’ve not been able to find any documentation for what #pred does, nor for any of the similar-looking things such as #abducible, #show and so on. What do they do?

I’m also having problems calling out to Prolog from SCASP, the README says to use the prolog/1 predicate but I can’t get it to work:

:- attach_packs(packs, [replace(true)]).
:- use_module(library(scasp)).
:- use_module(library(scasp/embed)).

is_even(X) :-
    0 is X mod 2.

:- begin_scasp(alan).

:- prolog (is_even/1) as opaque.

ok(X) :-
    candidate(X),
    is_even(X).  

candidate(1).
candidate(2).
candidate(3).

:- end_scasp.

Results in:

Warning: scasp.pl:20:
Warning:    scasp_predicate `(prolog)/1' does not exist
Warning: scasp.pl:20:
Warning:    scasp_predicate `is_even/1' does not exist

Thanks.

sCASP is primarily created by Joaquin Arias for Ciao Prolog. The SWI-Prolog implementation is is a port with some enhancements. It performs a lot better, it allows for embedding sCASP programs in Prolog programs and with some limitations the other way around and it extends the #pred directives. It is all not very well documented indeed :frowning:

Allows you to associate a natural language expression with the fact that some predicate is true. The SWI-Prolog implementation extends that to the HTML generator, so you can generate dedicated HTML for the justification tree.

creates a negative cycle that creates two possible worlds: one where the predicate is true and one where it is false.

Tells the system to include only the given predicates into the displayed model rather than all predicates.

That is old school. Just write normal Prolog code for things you want executed as sCASP (respecting the limitations of sCASP) and call scasp/2 or ?/1 with the various variations that dictate what is being displayed. Quite likely begin_scasp does not work any more.

As is, sCASP has a steep learning curve :frowning:

1 Like

As the SWI version is a port I’ve had a look at the Ciao docs to see if they helped, unless I’m missing something that’s not very well documented either, :frowning:

Thanks, that was my guess, I’m not sure I really grok the syntax though.

Ah, that perhaps explains why some of the examples are broken as they still use it.

It looked interesting because you get explanations “for free”, but it sounds like it’s only a toy, and the lack of working examples and documentation, and some documentation that’s just plain wrong, is a killer. Shame.

It is more than a toy, but less than what one should expect. To get started, load a program, e.g.

:- use_module(library(scasp)).

opera(D) :- not home(D).
home(D):- not opera(D).
home(monday).

false :- baby(D), opera(D).

baby(tuesday).

Load this into SWI-Prolog. Now you can do e.g.

108 ?- ? opera(D).
% s(CASP) model
{ not baby(_A),        not home(D),         opera(D),
  baby(tuesday),       home(tuesday),       not opera(tuesday)
},
D ∉ [monday,tuesday],
_A ∉ [tuesday] 

Or, for access from a program

107 ?- scasp(opera(D), [model(M), tree(T)]).
M = [not baby(_A), baby(tuesday), not home(D), home(tuesday), opera(D), not opera(tuesday)],
T = query-[goal_origin(opera(D), <clause>(0x4769b90))-[(not home(D))-[chs(opera(D))-[]]], o_nmr_check-[(not o_chk_1)-[(not baby(…))-[], goal_origin(…, …)-[], … - …]]],
D ∉ [monday,tuesday],
_A ∉ [tuesday] .

This allows you to reason about the model or justification tree.

1 Like

Thank you :slight_smile: I did manage to get the bird / penguin example working after my earlier post, pretty much exactly along the lines you describe. My next step will be to investigate performance - I have around 25k “symptom” facts that I need to reason across.

1 Like

In case it helps, there is a manual in Joaquin’s sCASP repo (a separate Ciao Prolog bundle).

2 Likes

Often not that good, though it depends more on the structure of the rules than the number of them. In general, sCASP is interesting if you have complicated negation and you need stable model semantics for this. It also deals with uncertainty in the sense of “I know this is true”, “I know this is false” or “I don’t know”. That can be modelled more lightweight in Prolog without sCASP, but you get it in the package.

sCASP explanation is a mere proof tree. It is easy enough to add that to Prolog. Explanation with tabling is a little harder.

The first question to ask is what kind of reasoning do you need? Now and in the future of your project.

Another way to look at these choices is to see whether you can model your data in the limited language sCASP offers. If yes, do so. You can then decide to execute the program under sCASP, plain Prolog or Prolog with tabling. Using a simple declarative specification allows for a lot of automated checking/rewriting/execution/…

2 Likes

Exactly so, that’s the pondering I’m doing at the moment :slight_smile: I’m building the system in layers:

  • Load a JSON snapshot of the state of a system and create a fact for each resource of interest in the JSON.
  • Create “link” facts between the resource facts based on knowledge of the relationships between resources, e.g. “Resource Type A holds the UID of associated resource type B in this field”.
  • Generic “symptom” rules, e.g. “If resource A has a reference to resource B, and B no longer exists, A is probably an orphan”
  • Resource-type specific “symptom” rules, e.g. “If this resource has been in this state for more than X hours, it’s broken” or “If attribute A of a resource has this value, attribute B must be one of these values”.

I then group all the symptoms for a given resource together, so I can see all its “brokenness” in once place. There’s a TUI that allows filtering and display of the aggregated symptoms. Although the facts and symptoms are generated dynamically from the incoming JSON, they don’t change once loaded, so I make heavy use of tabling. Once the initial data load & analysis is done, display and querying is very fast.

At a higher level, the JSON data describes multiple instances of “Systems”, where each system is implemented using a collection of resources of different types. The number of instances of a resource in each system can vary, but the overall “shape” of a system in terms of the types of and relationships between resources is known, but will need to be modelled - TBD.

The next phase, for which I was considering s(CASP), is to use the symptoms and the TBD model of the systems to reason about faults at a higher level, e.g. “If you get this error and a system has these symptoms, here’s what’s probably broken, and here’s how to investigate further / fix it” or “I can see these symptoms, that’s going to cause this problem if you don’t fix it, here’s how to do so”. For that I could probably roll up the detailed symptoms into summaries, whilst I’d need to retain resource UIDs etc to identify exactly what needed looking at once a problem has been identified, the initial reasoning might be possible with just “There’s N cases of Symptom A in System B”.

1 Like

That where I would start. Just try to write down the rules, not worrying too much about how they will be executed. Just try to express the knowledge in (Prolog) syntax, inventing names for building blocks you need that match the domain. Then you have something any domain expert can read and write. Next, worry about how to turn this into something executable.

2 Likes