Skip to content

Commit 73dd92e

Browse files
committed
updated equivalence notions for abstract argumentation
1 parent 5164ae9 commit 73dd92e

File tree

7 files changed

+290
-54
lines changed

7 files changed

+290
-54
lines changed

org-tweetyproject-arg-dung/src/main/java/org/tweetyproject/arg/dung/equivalence/LocalExpansionEquivalence.java

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@
1919
package org.tweetyproject.arg.dung.equivalence;
2020

2121
import org.tweetyproject.arg.dung.equivalence.kernel.EquivalenceKernel;
22+
import org.tweetyproject.arg.dung.reasoner.AbstractExtensionReasoner;
2223
import org.tweetyproject.arg.dung.reasoner.SimpleStableReasoner;
2324
import org.tweetyproject.arg.dung.semantics.Extension;
2425
import org.tweetyproject.arg.dung.semantics.Semantics;
2526
import org.tweetyproject.arg.dung.syntax.Argument;
27+
import org.tweetyproject.arg.dung.syntax.Attack;
2628
import org.tweetyproject.arg.dung.syntax.DungTheory;
29+
import org.tweetyproject.commons.util.SetTools;
2730

2831
import java.util.Collection;
2932
import java.util.HashSet;
33+
import java.util.Set;
3034

3135
/**
3236
* This class defines local (expansion) equivalence for {@link DungTheory argumentation frameworks} wrt. some {@link Semantics semantics},
@@ -41,6 +45,10 @@ public class LocalExpansionEquivalence implements Equivalence<DungTheory> {
4145

4246
private final Semantics semantics;
4347

48+
/**
49+
* Initializes a new instance of this equivalence notion
50+
* @param semantics some semantics
51+
*/
4452
public LocalExpansionEquivalence(Semantics semantics) {
4553
this.semantics = semantics;
4654
}
@@ -51,13 +59,11 @@ public boolean isEquivalent(DungTheory theory1, DungTheory theory2) {
5159
case ADM,PR,ID,UC,SST,EA -> {
5260
return new StrongEquivalence(Semantics.ADM).isEquivalent(theory1, theory2);
5361
}
54-
case GR -> {
62+
case GR,SAD -> {
5563
if (!new HashSet<>(theory1).equals(new HashSet<>(theory2))) {
56-
System.out.println("ARGS");
5764
return false;
5865
}
5966
if (!theory1.faf(new Extension<>()).equals(theory2.faf(new Extension<>()))) {
60-
System.out.println("FAF");
6167
return false;
6268
}
6369

@@ -66,54 +72,38 @@ public boolean isEquivalent(DungTheory theory1, DungTheory theory2) {
6672
if (S.size() == 1) {
6773
Argument a = S.iterator().next();
6874
if (isSelfLoopPathological(theory1.getReduct(a)) && isSelfLoopPathological(theory2.getReduct(a))) {
69-
System.out.println("SL_PAT");
7075
return true;
7176
}
7277

7378
if (!EquivalenceKernel.GROUNDED.getKernel(theory1.getReduct(a)).equals(EquivalenceKernel.GROUNDED.getKernel(theory2.getReduct(a)))) {
74-
System.out.println("RED_GR_KERN");
7579
return false;
7680
}
7781
Argument b1 = getBPathological(theory1);
7882
Argument b2 = getBPathological(theory2);
7983
if (b1 == null || !b1.equals(b2)) {
80-
System.out.println(b1.toString() + b2.toString());
8184
return false;
8285
}
8386
for (Argument d : theory1.getReduct(a).getAttackers(b1)) {
8487
if (!theory2.getReduct(a).isAttackedBy(b1,d)) {
85-
System.out.println("D_ATT_1");
8688
return false;
8789
}
8890
}
8991
for (Argument d : theory2.getReduct(a).getAttackers(b1)) {
9092
if (!theory1.getReduct(a).isAttackedBy(b1,d)) {
91-
System.out.println("D_ATT_2");
9293
return false;
9394
}
9495
}
9596
} else {
9697
for (Argument a : S) {
9798
if (!EquivalenceKernel.GROUNDED.getKernel(theory1.getReduct(a)).equals(EquivalenceKernel.GROUNDED.getKernel(theory2.getReduct(a)))) {
98-
System.out.println("GR_KERN");
9999
return false;
100100
}
101101
}
102102
}
103103
return true;
104104
}
105105
case CO -> {
106-
//if (EquivalenceKernel.LE_COMPLETE.getKernel(theory1).equals(EquivalenceKernel.LE_COMPLETE.getKernel(theory2))) {
107-
// Argument b = getBSaturated(theory1);
108-
// Argument b2 = getBSaturated(theory2);
109-
// if (b != null && b.equals(b2)) return true;
110-
//}
111-
if (!EquivalenceKernel.ADMISSIBLE.getKernel(theory1).equals(EquivalenceKernel.ADMISSIBLE.getKernel(theory2))) return false;
112-
if (!theory1.faf(new Extension<>()).equals(theory2.faf(new Extension<>()))) return false;
113-
//Argument b = getBSaturated(theory1);
114-
//if (b == null) return false;
115-
//if (!b.equals(getBSaturated(theory2))) return false;
116-
return true;
106+
return isLocalExpansionEquivalent(theory1, theory2, semantics);
117107
} case ST -> {
118108
if (EquivalenceKernel.STABLE.getKernel(theory1).equals(EquivalenceKernel.STABLE.getKernel(theory2))) {
119109
return true;
@@ -185,28 +175,35 @@ private Argument getBPathological(DungTheory theory) {
185175
return null;
186176
}
187177

188-
private boolean isBSaturated(DungTheory theory, Argument b) {
189-
if (theory.isAttackedBy(b,b)) return false;
190-
if (theory.getAttackers(b).isEmpty()) return false;
191-
for (Argument a : theory.getAttackers(b)) {
192-
if (!theory.isAttackedBy(a,a)) return false;
178+
/**
179+
* Naively checks whether two AFs are local equivalent by comparing the extensions of every local expansion
180+
*
181+
* @param theory1 some argumentation framework
182+
* @param theory2 some argumentation framework
183+
* @param semantics some semantics
184+
* @return 'true' iff both AFs are local equivalent under the given semantics
185+
*/
186+
public static boolean isLocalExpansionEquivalent(DungTheory theory1, DungTheory theory2, Semantics semantics) {
187+
if (!new HashSet<>(theory1.getNodes()).equals(new HashSet<>(theory2.getNodes()))) {
188+
return false;
193189
}
194-
for (Argument a : theory.getAttackers(b)) {
195-
for (Argument d : theory) {
196-
if (theory.isAttackedBy(d,d)) continue;
197-
if (!theory.isAttackedBy(a,d)) return false;
190+
AbstractExtensionReasoner reasoner = AbstractExtensionReasoner.getSimpleReasonerForSemantics(semantics);
191+
Set<Attack> attacks = new HashSet<>();
192+
for (Argument a: theory1) {
193+
for (Argument b: theory1) {
194+
attacks.add(new Attack(a,b));
198195
}
199-
200196
}
201-
return true;
202-
}
203-
204-
private Argument getBSaturated(DungTheory theory) {
205-
for (Argument b : theory) {
206-
if (isBSaturated(theory, b)) {
207-
return b;
197+
for (Set<Attack> subset: new SetTools<Attack>().subsets(attacks)) {
198+
DungTheory th1 = theory1.clone();
199+
th1.addAllAttacks(subset);
200+
DungTheory th2 = theory2.clone();
201+
th2.addAllAttacks(subset);
202+
if (!reasoner.getModels(th1).equals(reasoner.getModels(th2))) {
203+
//System.out.println(subset);
204+
return false;
208205
}
209206
}
210-
return null;
207+
return true;
211208
}
212209
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
* This file is part of "TweetyProject", a collection of Java libraries for
3+
* logical aspects of artificial intelligence and knowledge representation.
4+
*
5+
* TweetyProject is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License version 3 as
7+
* published by the Free Software Foundation.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*
17+
* Copyright 2025 The TweetyProject Team <http://tweetyproject.org/contact/>
18+
*/
19+
package org.tweetyproject.arg.dung.equivalence;
20+
21+
import org.tweetyproject.arg.dung.equivalence.kernel.EquivalenceKernel;
22+
import org.tweetyproject.arg.dung.reasoner.AbstractExtensionReasoner;
23+
import org.tweetyproject.arg.dung.semantics.Semantics;
24+
import org.tweetyproject.arg.dung.syntax.Argument;
25+
import org.tweetyproject.arg.dung.syntax.DungTheory;
26+
import org.tweetyproject.commons.util.SetTools;
27+
28+
import java.util.Collection;
29+
import java.util.HashSet;
30+
import java.util.Set;
31+
32+
33+
/**
34+
* This class defines normal deletion equivalence for {@link DungTheory argumentation frameworks} wrt. some {@link Semantics semantics},
35+
* i.e., two AFs F and G are normal deletion equivalent iff they possess the same set of
36+
* {@link org.tweetyproject.arg.dung.semantics.Extension extensions} wrt. the {@link Semantics semantics} under every normal deletion.
37+
* A normal deletion deletes a set of arguments together with all their corresponding attacks.
38+
*
39+
* @see "Ringo Baumann. 'Context-free and context-sensitive kernels: Update and deletion equivalence in abstract argumentation' ECAI14 (2014) pp. 63–68"
40+
*
41+
* @author Lars Bengel
42+
*/
43+
public class NormalDeletionEquivalence implements Equivalence<DungTheory> {
44+
/** the semantics of this equivalence instance **/
45+
private final Semantics semantics;
46+
47+
/**
48+
* Initializes a new instance of this equivalence wrt. the given semantics
49+
* @param semantics some semantics
50+
*/
51+
public NormalDeletionEquivalence(Semantics semantics) {
52+
this.semantics = semantics;
53+
}
54+
55+
@Override
56+
public boolean isEquivalent(DungTheory obj1, DungTheory obj2) {
57+
switch (semantics) {
58+
case CO,GR,SAD -> {
59+
if (!loop(obj1, obj2)) return false;
60+
if (!coAtt(obj1, obj2)) return false;
61+
Collection<Argument> shared = new SetTools<Argument>().getIntersection(new HashSet<>(obj1), new HashSet<>(obj2));
62+
EquivalenceKernel kernel = EquivalenceKernel.getStrongExpansionEquivalenceKernelForSemantics(semantics);
63+
return kernel.getKernel((DungTheory) obj1.getRestriction(shared)).equals(kernel.getKernel((DungTheory) obj2.getRestriction(shared)));
64+
} case ADM,PR,UC,ID -> {
65+
if (!loop(obj1, obj2)) return false;
66+
if (!admAtt(obj1, obj2)) return false;
67+
Collection<Argument> shared = new SetTools<Argument>().getIntersection(new HashSet<>(obj1), new HashSet<>(obj2));
68+
EquivalenceKernel kernel = EquivalenceKernel.getStrongExpansionEquivalenceKernelForSemantics(semantics);
69+
return kernel.getKernel((DungTheory) obj1.getRestriction(shared)).equals(kernel.getKernel((DungTheory) obj2.getRestriction(shared)));
70+
} case ST -> {
71+
return new StrongEquivalence(Semantics.ST).isEquivalent(obj1, obj2);
72+
} case SST,EA -> {
73+
return isNormalDeletionEquivalent(obj1,obj2,semantics);
74+
} default -> throw new IllegalArgumentException("unsupported semantics");
75+
}
76+
}
77+
78+
@Override
79+
public boolean isEquivalent(Collection<DungTheory> objects) {
80+
throw new UnsupportedOperationException("not implemented");
81+
}
82+
83+
@Override
84+
public String getName() {
85+
return "Normal Deletion Equivalence";
86+
}
87+
88+
/**
89+
* Naively checks whether two AFs are normal deletion equivalence by comparing the extensions of every normal deletion
90+
*
91+
* @param theory1 some argumentation framework
92+
* @param theory2 some argumentation framework
93+
* @param semantics some semantics
94+
* @return 'true' iff both AFs are normal deletion equivalent under the given semantics
95+
*/
96+
public static boolean isNormalDeletionEquivalent(DungTheory theory1, DungTheory theory2, Semantics semantics) {
97+
AbstractExtensionReasoner reasoner = AbstractExtensionReasoner.getSimpleReasonerForSemantics(semantics);
98+
Set<Argument> arguments = new HashSet<>(theory1);
99+
arguments.addAll(theory2);
100+
for (Set<Argument> subset: new SetTools<Argument>().subsets(arguments)) {
101+
DungTheory th1 = theory1.clone();
102+
th1.removeAll(subset);
103+
DungTheory th2 = theory2.clone();
104+
th2.removeAll(subset);
105+
if (!reasoner.getModels(th1).equals(reasoner.getModels(th2))) {
106+
//System.out.println(subset);
107+
//System.out.println(th1);
108+
//System.out.println(th2);
109+
return false;
110+
}
111+
}
112+
return true;
113+
}
114+
115+
private boolean loop(DungTheory theory1, DungTheory theory2) {
116+
Collection<Argument> symDif = new SetTools<Argument>().symmetricDifference(theory1, theory2);
117+
DungTheory combi = theory1.clone();
118+
combi.add(theory2);
119+
return symDif.equals(getSelfLoops((DungTheory) combi.getRestriction(symDif)));
120+
}
121+
122+
private boolean coAtt(DungTheory theory1, DungTheory theory2) {
123+
Collection<Argument> args1 = new HashSet<>(theory1);
124+
args1.removeAll(theory2);
125+
Collection<Argument> args2 = new HashSet<>(theory2);
126+
args2.removeAll(theory1);
127+
128+
for (Argument b: args1) {
129+
for (Argument a: getNonSelfLoops((DungTheory) theory1.getRestriction(new SetTools<Argument>().getIntersection(new HashSet<>(theory1), new HashSet<>(theory2))))) {
130+
if (theory1.isAttackedBy(a,b)) {
131+
return false;
132+
}
133+
}
134+
}
135+
for (Argument b: args2) {
136+
for (Argument a: getNonSelfLoops((DungTheory) theory2.getRestriction(new SetTools<Argument>().getIntersection(new HashSet<>(theory1), new HashSet<>(theory2))))) {
137+
if (theory2.isAttackedBy(a,b)) {
138+
return false;
139+
}
140+
}
141+
}
142+
return true;
143+
}
144+
145+
private boolean admAtt(DungTheory theory1, DungTheory theory2) {
146+
Collection<Argument> args1 = new HashSet<>(theory1);
147+
args1.removeAll(theory2);
148+
Collection<Argument> args2 = new HashSet<>(theory2);
149+
args2.removeAll(theory1);
150+
151+
for (Argument b: args1) {
152+
for (Argument a: getNonSelfLoops((DungTheory) theory1.getRestriction(new SetTools<Argument>().getIntersection(new HashSet<>(theory1), new HashSet<>(theory2))))) {
153+
if (theory1.isAttackedBy(a,b) && !theory1.isAttackedBy(b,a)) {
154+
return false;
155+
}
156+
}
157+
}
158+
for (Argument b: args2) {
159+
for (Argument a: getNonSelfLoops((DungTheory) theory2.getRestriction(new SetTools<Argument>().getIntersection(new HashSet<>(theory1), new HashSet<>(theory2))))) {
160+
if (theory2.isAttackedBy(a,b) && !theory2.isAttackedBy(b,a)) {
161+
return false;
162+
}
163+
}
164+
}
165+
return true;
166+
}
167+
168+
private Collection<Argument> getSelfLoops(DungTheory theory) {
169+
Collection<Argument> result = new HashSet<>();
170+
for (Argument arg : theory) {
171+
if (theory.isAttackedBy(arg,arg)) {
172+
result.add(arg);
173+
}
174+
}
175+
return result;
176+
}
177+
178+
private Collection<Argument> getNonSelfLoops(DungTheory theory) {
179+
Collection<Argument> result = new HashSet<>();
180+
for (Argument arg : theory) {
181+
if (!theory.isAttackedBy(arg,arg)) {
182+
result.add(arg);
183+
}
184+
}
185+
return result;
186+
}
187+
}

org-tweetyproject-arg-dung/src/main/java/org/tweetyproject/arg/dung/equivalence/SerialisationEquivalence.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
* i.e., two AFs are serialisation equivalent iff they possess the same set of
3030
* {@link org.tweetyproject.arg.dung.serialisability.semantics.SerialisationSequence Serialisation Sequences} wrt. some {@link Semantics}.
3131
*
32+
* @see "Lars Bengel, Julian Sander, Matthias Thimm. 'Characterising serialisation equivalence for abstract argumentation' ECAI24 (2024) pp. 3340–334"
33+
*
3234
* @author Julian Sander
3335
* @author Lars Bengel
3436
*/

org-tweetyproject-arg-dung/src/main/java/org/tweetyproject/arg/dung/equivalence/WeakExpansionEquivalence.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public class WeakExpansionEquivalence implements Equivalence<DungTheory> {
4747
private final Semantics semantics;
4848

4949
/**
50-
* Initializes a new instance of equivalence wrt. the given semantics
50+
* Initializes a new instance of this equivalence wrt. the given semantics
5151
* @param semantics some semantics
5252
*/
5353
public WeakExpansionEquivalence(Semantics semantics) {
@@ -57,7 +57,7 @@ public WeakExpansionEquivalence(Semantics semantics) {
5757
@Override
5858
public boolean isEquivalent(DungTheory theory1, DungTheory theory2) {
5959
switch (semantics) {
60-
case ADM,PR,CO,GR -> {
60+
case ADM,PR,CO,GR,SAD -> {
6161
Collection<Extension<DungTheory>> exts1 = AbstractExtensionReasoner.getSimpleReasonerForSemantics(semantics).getModels(theory1);
6262
Collection<Extension<DungTheory>> exts2 = AbstractExtensionReasoner.getSimpleReasonerForSemantics(semantics).getModels(theory2);
6363
if (!new HashSet<>(theory1).equals(new HashSet<>(theory2))) return false;

org-tweetyproject-arg-dung/src/main/java/org/tweetyproject/arg/dung/equivalence/kernel/EquivalenceKernel.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,25 @@ public static EquivalenceKernel getStrongEquivalenceKernelForSemantics(Semantics
9898
default -> throw new IllegalArgumentException("No kernel exists for semantics: " + semantics);
9999
}
100100
}
101+
102+
public static EquivalenceKernel getStrongExpansionEquivalenceKernelForSemantics(Semantics semantics) {
103+
switch (semantics) {
104+
case SST,EA -> {
105+
return ADMISSIBLE;
106+
}
107+
case ST -> {
108+
return STABLE;
109+
}
110+
case ADM,PR,ID,UC -> {
111+
return SE_ADMISSIBLE;
112+
}
113+
case GR,SAD -> {
114+
return SE_GROUNDED;
115+
}
116+
case CO -> {
117+
return SE_COMPLETE;
118+
}
119+
default -> throw new IllegalArgumentException("No kernel defined for semantics: " + semantics);
120+
}
121+
}
101122
}

0 commit comments

Comments
 (0)