youssef commited on
Commit
8bdd43d
·
1 Parent(s): d02e800

reformatting

Browse files
aba/aba_framework.py CHANGED
@@ -18,6 +18,7 @@ from .attacks import Attacks
18
  from collections import deque, defaultdict
19
  from itertools import combinations, product
20
 
 
21
  class ABAFramework:
22
  """
23
  Formal specification and implementation of Assumption-Based Argumentation (ABA) frameworks
@@ -36,7 +37,7 @@ class ABAFramework:
36
  reverse_attacks (set[tuple]): Reverse ABA+ attacks due to preferences.
37
  assumption_combinations (list[set[Literal]]): All subsets of base assumptions.
38
 
39
-
40
  Mathematical foundation :
41
 
42
  An ABA framework is a tuple ⟨L, R, A, C⟩ where:
@@ -74,10 +75,13 @@ class ABAFramework:
74
  )
75
 
76
  def __str__(self):
77
- language_str = ', '.join(str(l) for l in sorted(self.language, key=str))
 
78
  rules_str = '\n'.join(str(r) for r in sorted(self.rules, key=str))
79
- assumptions_str = ', '.join(str(a) for a in sorted(self.assumptions, key=str))
80
- contraries_str = ', '.join(str(c) for c in sorted(self.contraries, key=str))
 
 
81
  result = [
82
  f"L = {{{language_str}}}",
83
  f"R = {{\n{rules_str}\n}}",
@@ -85,14 +89,16 @@ class ABAFramework:
85
  f"CONTRARIES = {{{contraries_str}}}"
86
  ]
87
  if self.preferences:
88
- sorted_prefs = sorted(self.preferences.items(), key=lambda x: str(x[0]))
 
89
  preferences_str = '\n'.join(
90
  f" {str(literal)} > {{{', '.join(str(p) for p in sorted(prefs, key=str))}}}"
91
  for literal, prefs in sorted_prefs
92
  )
93
  result.append(f"PREFERENCES:\n{preferences_str}")
94
  if self.arguments:
95
- arguments_str = '\n'.join(str(arg) for arg in sorted(self.arguments, key=str))
 
96
  result.append(f"ARGS:\n{arguments_str}")
97
  return '\n'.join(result)
98
 
@@ -181,10 +187,8 @@ class ABAFramework:
181
  if arg1.claim == contrary.contrary_attacker and contrary.contraried_literal in arg2.leaves:
182
  self.attacks.add(Attacks(arg1, arg2))
183
 
184
-
185
-
186
  # ------------------------- ABA Methods -------------------------
187
-
188
  def transform_aba(self) -> None:
189
  """
190
  Transforms the ABA framework to ensure it is both non-circular and atomic.
@@ -225,7 +229,7 @@ class ABAFramework:
225
  L = {a, b, x}
226
  A = {a, b}
227
  R = { r1: a <- x }
228
-
229
  After _make_aba_atomic():
230
  L = {a, b, x, xd, xnd}
231
  A = {a, b, xd, xnd}
@@ -278,7 +282,7 @@ class ABAFramework:
278
  if rule.body and not all(lit in self.assumptions for lit in rule.body):
279
  return False
280
  return True
281
-
282
  def is_aba_circular(self) -> bool:
283
  """
284
  Checks if the ABA framework is circular by detecting cycles in the rule dependency graph.
@@ -330,7 +334,7 @@ class ABAFramework:
330
  if has_cycle(lit, visited, set()):
331
  return True # Cycle found
332
  return False # No cycles
333
-
334
  def make_aba_not_circular(self) -> None:
335
  """
336
  Transforms the ABA framework to a non-circular one by renaming heads and bodies of rules.
@@ -364,7 +368,6 @@ class ABAFramework:
364
  x1 <- a
365
  x <- a
366
  """
367
-
368
 
369
  k = len(self.language) - len(self.assumptions)
370
  new_language = set(self.language)
@@ -392,10 +395,8 @@ class ABAFramework:
392
  new_rule_name = f"{rule.rule_name}_{i+1}"
393
  new_rules.add(Rule(new_rule_name, new_head, new_body))
394
 
395
-
396
  self.language = new_language
397
  self.rules = new_rules
398
-
399
 
400
  # ------------------------- ABA+ Methods -------------------------
401
 
@@ -406,7 +407,7 @@ class ABAFramework:
406
  ABA+ extends classical ABA by incorporating preference information over assumptions directly into
407
  the attack relation, allowing for attack reversal when a target assumption is preferred over an
408
  attacking assumption.
409
-
410
  Procedure:
411
  1. Ensures base_assumptions is set (preserves original assumptions before any transformation).
412
  2. Generates all possible subsets of base assumptions (the power set).
@@ -424,15 +425,17 @@ class ABAFramework:
424
  on the generated arguments to determine attacks between assumption sets.
425
  """
426
 
427
-
428
  if not getattr(self, "base_assumptions", None):
429
  self.base_assumptions = set(self.assumptions)
430
  self.assumption_combinations = self.generate_assumption_combinations()
431
- print(f"Generated {len(self.assumption_combinations)} assumption combinations")
432
-
 
433
  self.generate_normal_reverse_attacks()
434
- print(f"Generated {len(self.normal_attacks)} normal attacks (assumption sets)")
435
- print(f"Generated {len(self.reverse_attacks)} reverse attacks (assumption sets)")
 
 
436
 
437
  def generate_assumption_combinations(self) -> list[set[Literal]]:
438
  """
@@ -462,7 +465,8 @@ class ABAFramework:
462
  For n base assumptions, this generates 2^n combinations. The computational complexity
463
  can become significant for large assumption sets.
464
  """
465
- source_assumptions = getattr(self, "base_assumptions", self.assumptions)
 
466
  all_combos = []
467
  for r in range(len(source_assumptions) + 1):
468
  for combo in combinations(source_assumptions, r):
@@ -555,27 +559,30 @@ class ABAFramework:
555
 
556
  for X in self.assumption_combinations:
557
  for Y in self.assumption_combinations:
558
-
559
  args_X = self.arguments_from_assumptions(X)
560
  args_Y = self.arguments_from_assumptions(Y)
561
  if not args_X or not args_Y:
562
  continue
563
-
564
  # Check for attacks from X to Y
565
  for ax in args_X:
566
  for ay in args_Y:
567
  for contrary in self.contraries:
568
  if ax.claim == contrary.contrary_attacker and contrary.contraried_literal in ay.leaves:
569
- reverse = any(self.is_preferred(y, x) for y in Y for x in X)
 
570
  if reverse:
571
- self.reverse_attacks.add((frozenset(Y), frozenset(X)))
 
572
  else:
573
- self.normal_attacks.add((frozenset(X), frozenset(Y)))
574
-
 
575
  # Now add the subset attacks: if (ab) attacks c, then (abc) should also attack c
576
  additional_normal = set()
577
  additional_reverse = set()
578
-
579
  # For normal attacks: if X attacks Y, then any superset of X should attack Y
580
  for X_att, Y_att in self.normal_attacks:
581
  X = set(X_att)
@@ -583,7 +590,7 @@ class ABAFramework:
583
  for Z in self.assumption_combinations:
584
  if X.issubset(Z) and Z != X:
585
  additional_normal.add((frozenset(Z), Y_att))
586
-
587
  # For reverse attacks: if Y attacks X, then any superset of Y should attack X
588
  for Y_att, X_att in self.reverse_attacks:
589
  Y = set(Y_att)
@@ -591,7 +598,7 @@ class ABAFramework:
591
  for Z in self.assumption_combinations:
592
  if Y.issubset(Z) and Z != Y:
593
  additional_reverse.add((frozenset(Z), X_att))
594
-
595
  # Add the additional attacks
596
  self.normal_attacks.update(additional_normal)
597
  self.reverse_attacks.update(additional_reverse)
 
18
  from collections import deque, defaultdict
19
  from itertools import combinations, product
20
 
21
+
22
  class ABAFramework:
23
  """
24
  Formal specification and implementation of Assumption-Based Argumentation (ABA) frameworks
 
37
  reverse_attacks (set[tuple]): Reverse ABA+ attacks due to preferences.
38
  assumption_combinations (list[set[Literal]]): All subsets of base assumptions.
39
 
40
+
41
  Mathematical foundation :
42
 
43
  An ABA framework is a tuple ⟨L, R, A, C⟩ where:
 
75
  )
76
 
77
  def __str__(self):
78
+ language_str = ', '.join(str(l)
79
+ for l in sorted(self.language, key=str))
80
  rules_str = '\n'.join(str(r) for r in sorted(self.rules, key=str))
81
+ assumptions_str = ', '.join(str(a)
82
+ for a in sorted(self.assumptions, key=str))
83
+ contraries_str = ', '.join(str(c)
84
+ for c in sorted(self.contraries, key=str))
85
  result = [
86
  f"L = {{{language_str}}}",
87
  f"R = {{\n{rules_str}\n}}",
 
89
  f"CONTRARIES = {{{contraries_str}}}"
90
  ]
91
  if self.preferences:
92
+ sorted_prefs = sorted(self.preferences.items(),
93
+ key=lambda x: str(x[0]))
94
  preferences_str = '\n'.join(
95
  f" {str(literal)} > {{{', '.join(str(p) for p in sorted(prefs, key=str))}}}"
96
  for literal, prefs in sorted_prefs
97
  )
98
  result.append(f"PREFERENCES:\n{preferences_str}")
99
  if self.arguments:
100
+ arguments_str = '\n'.join(str(arg)
101
+ for arg in sorted(self.arguments, key=str))
102
  result.append(f"ARGS:\n{arguments_str}")
103
  return '\n'.join(result)
104
 
 
187
  if arg1.claim == contrary.contrary_attacker and contrary.contraried_literal in arg2.leaves:
188
  self.attacks.add(Attacks(arg1, arg2))
189
 
 
 
190
  # ------------------------- ABA Methods -------------------------
191
+
192
  def transform_aba(self) -> None:
193
  """
194
  Transforms the ABA framework to ensure it is both non-circular and atomic.
 
229
  L = {a, b, x}
230
  A = {a, b}
231
  R = { r1: a <- x }
232
+
233
  After _make_aba_atomic():
234
  L = {a, b, x, xd, xnd}
235
  A = {a, b, xd, xnd}
 
282
  if rule.body and not all(lit in self.assumptions for lit in rule.body):
283
  return False
284
  return True
285
+
286
  def is_aba_circular(self) -> bool:
287
  """
288
  Checks if the ABA framework is circular by detecting cycles in the rule dependency graph.
 
334
  if has_cycle(lit, visited, set()):
335
  return True # Cycle found
336
  return False # No cycles
337
+
338
  def make_aba_not_circular(self) -> None:
339
  """
340
  Transforms the ABA framework to a non-circular one by renaming heads and bodies of rules.
 
368
  x1 <- a
369
  x <- a
370
  """
 
371
 
372
  k = len(self.language) - len(self.assumptions)
373
  new_language = set(self.language)
 
395
  new_rule_name = f"{rule.rule_name}_{i+1}"
396
  new_rules.add(Rule(new_rule_name, new_head, new_body))
397
 
 
398
  self.language = new_language
399
  self.rules = new_rules
 
400
 
401
  # ------------------------- ABA+ Methods -------------------------
402
 
 
407
  ABA+ extends classical ABA by incorporating preference information over assumptions directly into
408
  the attack relation, allowing for attack reversal when a target assumption is preferred over an
409
  attacking assumption.
410
+
411
  Procedure:
412
  1. Ensures base_assumptions is set (preserves original assumptions before any transformation).
413
  2. Generates all possible subsets of base assumptions (the power set).
 
425
  on the generated arguments to determine attacks between assumption sets.
426
  """
427
 
 
428
  if not getattr(self, "base_assumptions", None):
429
  self.base_assumptions = set(self.assumptions)
430
  self.assumption_combinations = self.generate_assumption_combinations()
431
+ print(
432
+ f"Generated {len(self.assumption_combinations)} assumption combinations")
433
+
434
  self.generate_normal_reverse_attacks()
435
+ print(
436
+ f"Generated {len(self.normal_attacks)} normal attacks (assumption sets)")
437
+ print(
438
+ f"Generated {len(self.reverse_attacks)} reverse attacks (assumption sets)")
439
 
440
  def generate_assumption_combinations(self) -> list[set[Literal]]:
441
  """
 
465
  For n base assumptions, this generates 2^n combinations. The computational complexity
466
  can become significant for large assumption sets.
467
  """
468
+ source_assumptions = getattr(
469
+ self, "base_assumptions", self.assumptions)
470
  all_combos = []
471
  for r in range(len(source_assumptions) + 1):
472
  for combo in combinations(source_assumptions, r):
 
559
 
560
  for X in self.assumption_combinations:
561
  for Y in self.assumption_combinations:
562
+
563
  args_X = self.arguments_from_assumptions(X)
564
  args_Y = self.arguments_from_assumptions(Y)
565
  if not args_X or not args_Y:
566
  continue
567
+
568
  # Check for attacks from X to Y
569
  for ax in args_X:
570
  for ay in args_Y:
571
  for contrary in self.contraries:
572
  if ax.claim == contrary.contrary_attacker and contrary.contraried_literal in ay.leaves:
573
+ reverse = any(self.is_preferred(y, x)
574
+ for y in Y for x in X)
575
  if reverse:
576
+ self.reverse_attacks.add(
577
+ (frozenset(Y), frozenset(X)))
578
  else:
579
+ self.normal_attacks.add(
580
+ (frozenset(X), frozenset(Y)))
581
+
582
  # Now add the subset attacks: if (ab) attacks c, then (abc) should also attack c
583
  additional_normal = set()
584
  additional_reverse = set()
585
+
586
  # For normal attacks: if X attacks Y, then any superset of X should attack Y
587
  for X_att, Y_att in self.normal_attacks:
588
  X = set(X_att)
 
590
  for Z in self.assumption_combinations:
591
  if X.issubset(Z) and Z != X:
592
  additional_normal.add((frozenset(Z), Y_att))
593
+
594
  # For reverse attacks: if Y attacks X, then any superset of Y should attack X
595
  for Y_att, X_att in self.reverse_attacks:
596
  Y = set(Y_att)
 
598
  for Z in self.assumption_combinations:
599
  if Y.issubset(Z) and Z != Y:
600
  additional_reverse.add((frozenset(Z), X_att))
601
+
602
  # Add the additional attacks
603
  self.normal_attacks.update(additional_normal)
604
  self.reverse_attacks.update(additional_reverse)
aba/exemples/atomic.txt CHANGED
@@ -1,4 +1,3 @@
1
-
2
  L: [a,b,p,q,r]
3
  A: [a,b]
4
  C(a): r
 
 
1
  L: [a,b,p,q,r]
2
  A: [a,b]
3
  C(a): r
aba/exemples/td4_1.txt CHANGED
@@ -1,4 +1,3 @@
1
-
2
  L: [a,b,l,s]
3
  A: [a,b]
4
  [r1]: l <- a
 
 
1
  L: [a,b,l,s]
2
  A: [a,b]
3
  [r1]: l <- a
aba/exemples/td4_2.txt CHANGED
@@ -1,4 +1,3 @@
1
-
2
  L: [a,b,l,s,y]
3
  A: [a,b,y]
4
  C(a): s
 
 
1
  L: [a,b,l,s,y]
2
  A: [a,b,y]
3
  C(a): s
aba/exemples/td4_2and.txt CHANGED
@@ -1,4 +1,3 @@
1
-
2
  L: [a,b,l,s,y]
3
  A: [a,b,y]
4
  C(a): s
 
 
1
  L: [a,b,l,s,y]
2
  A: [a,b,y]
3
  C(a): s