Examples

Complete theories you can paste into the IDE or the Playground and run as they are. Each one isolates a single feature of the framework.

Most of them carry a Try it link that opens the example already loaded in the Web Playground, so you can run it without copying anything.


Conflicting premises

The smallest interesting theory: two premises supporting opposite conclusions.

f1 :=> d.
f2 :=> -d.
?- arg2p::solve(d, Res).

Res = [und(d)]

Both conclusions are UND. Neither argument defeats the other, so neither can be accepted.

Try it


Resolving a conflict with preferences

Adding a superiority relation breaks the tie:

f1 :=> d.
f2 :=> -d.
sup(f1, f2).
?- arg2p::solve(d, Res).

Res = [in(d)]

d is now IN and -d is OUT. Preference handling is active by default through graphExtension(standardPref); see Flags for the other preference models.

Try it


Strict rules and axioms

Strict rules (->) cannot be defeated, and axioms (:->) are premises that cannot be questioned:

a1 :-> bird(tweety).
r1 : bird(X) -> animal(X).
r2 : bird(X) => flies(X).
r3 : penguin(X) => -flies(X).

animal(tweety) follows strictly, so no argument can attack it. flies(tweety), derived defeasibly, remains open to attack.

Try it


Exceptions with weak negation

Weak negation expresses “unless we know otherwise”:

r1 : bird(X), ~(penguin(X)) => flies(X).
f1 :=> bird(tweety).
f2 :=> penguin(tweety).

The premise ~(penguin(tweety)) fails, so r1 never applies to Tweety and flies(tweety) is not concluded.

Try it


Undercutting a rule

An undercut attacks the applicability of a rule rather than its conclusion:

r1 : witness_says(X) => reliable(X).
r2 : unreliable(witness) => undercut(r1).
f1 :=> witness_says(story).
f2 :=> unreliable(witness).

r2 disables r1, so reliable(story) is not accepted, even though nothing argues against the story directly.

Try it


Obligations and violations

The deontic operators express prohibitions and the violations that follow from breaking them:

f1 :=> o(-enter).
f2 :=> enter.
v_rule : o(-enter), enter => violation.

The obligation not to enter, together with the fact of entering, yields violation.

Try it


Querying a single goal

Instead of computing every labelling, ask about one conclusion. This uses the goal-directed evaluation enabled by queryMode:

f1 :=> d.
f2 :=> -d.
?- arg2p::answerQuery(d, In, Out, Und).

Only the part of the graph relevant to d is built, which matters on large theories. When the three separate sets are not needed, arg2p::solve(d, Res) returns the same information as a single list.

Try it


Choosing a different semantics

Grounded semantics returns exactly one labelling. Semantics such as preferred may return several, one per solution:

argumentLabellingMode(preferred).

f1 :=> a.
f2 :=> -a.

Asking for all solutions yields two labellings: one accepting a, one accepting -a. In Kotlin, iterate over the sequence rather than taking first().

Try it — the link carries the whole flag block, since a shared link replaces the flags editor wholesale.


Evaluating an abstract framework

When you already have arguments and attacks and do not need to build them from rules:

?- abstract::solve([a, b, c], [(a, b), (b, c)], I, O, U).

I = [a, c],
O = [b],
U = [].

See Abstract Evaluation.

Try it — this one opens the playground in Abstract mode with the framework already drawn.


Burden of persuasion

A statement carrying the burden of persuasion has to be established: when the arguments for and against it cancel out, it fails instead of staying undecided. The burden is declared with bp/1 and evaluated by the bp_grounded family of semantics:

argumentLabellingMode(bp_grounded).

bp(guilty).
r1 : evidence => guilty.
r2 : alibi => -guilty.
f1 :=> evidence.
f2 :=> alibi.
?- arg2p::solve(guilty, Res).

Res = [out(guilty)]

The evidence and the alibi defeat each other, so without a burden guilty would be UND. The burden resolves the deadlock against the party carrying it, and guilty comes out OUT.

Try it


Causal questions

With the causality module, you can ask whether something caused something else:

f_1 :=> fire_a.
f_2 :=> fire_b.
r_1 : fire_a => house_burns.
r_2 : fire_b => house_burns.
?- context_reset, causality::ness(X, fire_a, house_burns).

Try it

The but-for test fails here — the house burns either way — while the NESS test succeeds, binding X to the intervention under which fire_a really is necessary.