arg2p 0.19.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. arg2p/__init__.py +63 -0
  2. arg2p/__main__.py +49 -0
  3. arg2p/_jvm.py +145 -0
  4. arg2p/_version.py +2 -0
  5. arg2p/arg2p.py +271 -0
  6. arg2p/flags.py +224 -0
  7. arg2p/jars/Java-WebSocket-1.6.0.jar +0 -0
  8. arg2p/jars/annotations-13.0.jar +0 -0
  9. arg2p/jars/arg2p-jvm-0.19.0.jar +0 -0
  10. arg2p/jars/causality-solver-jvm-0.19.0.jar +0 -0
  11. arg2p/jars/core-jvm-0.19.0.jar +0 -0
  12. arg2p/jars/core-jvm-3.0.5.jar +0 -0
  13. arg2p/jars/dsl-core-jvm-3.0.5.jar +0 -0
  14. arg2p/jars/dsl-solve-jvm-3.0.5.jar +0 -0
  15. arg2p/jars/dsl-theory-jvm-3.0.5.jar +0 -0
  16. arg2p/jars/dsl-unify-jvm-3.0.5.jar +0 -0
  17. arg2p/jars/io-lib-jvm-3.0.5.jar +0 -0
  18. arg2p/jars/kotlin-reflect-2.4.21.jar +0 -0
  19. arg2p/jars/kotlin-stdlib-2.4.21.jar +0 -0
  20. arg2p/jars/kotlin-stdlib-jdk7-2.4.21.jar +0 -0
  21. arg2p/jars/kotlin-stdlib-jdk8-2.4.21.jar +0 -0
  22. arg2p/jars/kt-math-jvm-0.10.2.jar +0 -0
  23. arg2p/jars/okio-jvm-3.18.2.jar +0 -0
  24. arg2p/jars/parallel-solver-jvm-0.19.0.jar +0 -0
  25. arg2p/jars/parser-core-jvm-3.0.5.jar +0 -0
  26. arg2p/jars/parser-impl-jvm-3.0.5.jar +0 -0
  27. arg2p/jars/parser-theory-jvm-3.0.5.jar +0 -0
  28. arg2p/jars/slf4j-api-2.0.13.jar +0 -0
  29. arg2p/jars/solve-jvm-3.0.5.jar +0 -0
  30. arg2p/jars/theory-jvm-3.0.5.jar +0 -0
  31. arg2p/jars/unify-jvm-3.0.5.jar +0 -0
  32. arg2p/jars/utils-jvm-3.0.5.jar +0 -0
  33. arg2p/jre/bin/api-ms-win-core-console-l1-1-0.dll +0 -0
  34. arg2p/jre/bin/api-ms-win-core-console-l1-2-0.dll +0 -0
  35. arg2p/jre/bin/api-ms-win-core-datetime-l1-1-0.dll +0 -0
  36. arg2p/jre/bin/api-ms-win-core-debug-l1-1-0.dll +0 -0
  37. arg2p/jre/bin/api-ms-win-core-errorhandling-l1-1-0.dll +0 -0
  38. arg2p/jre/bin/api-ms-win-core-fibers-l1-1-0.dll +0 -0
  39. arg2p/jre/bin/api-ms-win-core-fibers-l1-1-1.dll +0 -0
  40. arg2p/jre/bin/api-ms-win-core-file-l1-1-0.dll +0 -0
  41. arg2p/jre/bin/api-ms-win-core-file-l1-2-0.dll +0 -0
  42. arg2p/jre/bin/api-ms-win-core-file-l2-1-0.dll +0 -0
  43. arg2p/jre/bin/api-ms-win-core-handle-l1-1-0.dll +0 -0
  44. arg2p/jre/bin/api-ms-win-core-heap-l1-1-0.dll +0 -0
  45. arg2p/jre/bin/api-ms-win-core-interlocked-l1-1-0.dll +0 -0
  46. arg2p/jre/bin/api-ms-win-core-kernel32-legacy-l1-1-1.dll +0 -0
  47. arg2p/jre/bin/api-ms-win-core-libraryloader-l1-1-0.dll +0 -0
  48. arg2p/jre/bin/api-ms-win-core-localization-l1-2-0.dll +0 -0
  49. arg2p/jre/bin/api-ms-win-core-memory-l1-1-0.dll +0 -0
  50. arg2p/jre/bin/api-ms-win-core-namedpipe-l1-1-0.dll +0 -0
  51. arg2p/jre/bin/api-ms-win-core-processenvironment-l1-1-0.dll +0 -0
  52. arg2p/jre/bin/api-ms-win-core-processthreads-l1-1-0.dll +0 -0
  53. arg2p/jre/bin/api-ms-win-core-processthreads-l1-1-1.dll +0 -0
  54. arg2p/jre/bin/api-ms-win-core-profile-l1-1-0.dll +0 -0
  55. arg2p/jre/bin/api-ms-win-core-rtlsupport-l1-1-0.dll +0 -0
  56. arg2p/jre/bin/api-ms-win-core-string-l1-1-0.dll +0 -0
  57. arg2p/jre/bin/api-ms-win-core-synch-l1-1-0.dll +0 -0
  58. arg2p/jre/bin/api-ms-win-core-synch-l1-2-0.dll +0 -0
  59. arg2p/jre/bin/api-ms-win-core-sysinfo-l1-1-0.dll +0 -0
  60. arg2p/jre/bin/api-ms-win-core-sysinfo-l1-2-0.dll +0 -0
  61. arg2p/jre/bin/api-ms-win-core-timezone-l1-1-0.dll +0 -0
  62. arg2p/jre/bin/api-ms-win-core-util-l1-1-0.dll +0 -0
  63. arg2p/jre/bin/api-ms-win-crt-conio-l1-1-0.dll +0 -0
  64. arg2p/jre/bin/api-ms-win-crt-convert-l1-1-0.dll +0 -0
  65. arg2p/jre/bin/api-ms-win-crt-environment-l1-1-0.dll +0 -0
  66. arg2p/jre/bin/api-ms-win-crt-filesystem-l1-1-0.dll +0 -0
  67. arg2p/jre/bin/api-ms-win-crt-heap-l1-1-0.dll +0 -0
  68. arg2p/jre/bin/api-ms-win-crt-locale-l1-1-0.dll +0 -0
  69. arg2p/jre/bin/api-ms-win-crt-math-l1-1-0.dll +0 -0
  70. arg2p/jre/bin/api-ms-win-crt-multibyte-l1-1-0.dll +0 -0
  71. arg2p/jre/bin/api-ms-win-crt-private-l1-1-0.dll +0 -0
  72. arg2p/jre/bin/api-ms-win-crt-process-l1-1-0.dll +0 -0
  73. arg2p/jre/bin/api-ms-win-crt-runtime-l1-1-0.dll +0 -0
  74. arg2p/jre/bin/api-ms-win-crt-stdio-l1-1-0.dll +0 -0
  75. arg2p/jre/bin/api-ms-win-crt-string-l1-1-0.dll +0 -0
  76. arg2p/jre/bin/api-ms-win-crt-time-l1-1-0.dll +0 -0
  77. arg2p/jre/bin/api-ms-win-crt-utility-l1-1-0.dll +0 -0
  78. arg2p/jre/bin/java.dll +0 -0
  79. arg2p/jre/bin/java.exe +0 -0
  80. arg2p/jre/bin/javaw.exe +0 -0
  81. arg2p/jre/bin/jimage.dll +0 -0
  82. arg2p/jre/bin/jli.dll +0 -0
  83. arg2p/jre/bin/keytool.exe +0 -0
  84. arg2p/jre/bin/management.dll +0 -0
  85. arg2p/jre/bin/msvcp140.dll +0 -0
  86. arg2p/jre/bin/net.dll +0 -0
  87. arg2p/jre/bin/nio.dll +0 -0
  88. arg2p/jre/bin/server/jvm.dll +0 -0
  89. arg2p/jre/bin/syslookup.dll +0 -0
  90. arg2p/jre/bin/ucrtbase.dll +0 -0
  91. arg2p/jre/bin/vcruntime140.dll +0 -0
  92. arg2p/jre/bin/vcruntime140_1.dll +0 -0
  93. arg2p/jre/bin/verify.dll +0 -0
  94. arg2p/jre/bin/zip.dll +0 -0
  95. arg2p/jre/conf/jaxp.properties +180 -0
  96. arg2p/jre/conf/logging.properties +63 -0
  97. arg2p/jre/conf/net.properties +168 -0
  98. arg2p/jre/conf/security/java.policy +46 -0
  99. arg2p/jre/conf/security/java.security +1650 -0
  100. arg2p/jre/conf/security/policy/README.txt +54 -0
  101. arg2p/jre/conf/security/policy/limited/default_US_export.policy +6 -0
  102. arg2p/jre/conf/security/policy/limited/default_local.policy +14 -0
  103. arg2p/jre/conf/security/policy/limited/exempt_local.policy +13 -0
  104. arg2p/jre/conf/security/policy/unlimited/default_US_export.policy +6 -0
  105. arg2p/jre/conf/security/policy/unlimited/default_local.policy +6 -0
  106. arg2p/jre/legal/java.base/ADDITIONAL_LICENSE_INFO +37 -0
  107. arg2p/jre/legal/java.base/ASSEMBLY_EXCEPTION +27 -0
  108. arg2p/jre/legal/java.base/LICENSE +347 -0
  109. arg2p/jre/legal/java.base/aes.md +36 -0
  110. arg2p/jre/legal/java.base/asm.md +36 -0
  111. arg2p/jre/legal/java.base/c-libutl.md +35 -0
  112. arg2p/jre/legal/java.base/cldr.md +109 -0
  113. arg2p/jre/legal/java.base/icu.md +518 -0
  114. arg2p/jre/legal/java.base/public_suffix.md +399 -0
  115. arg2p/jre/legal/java.base/siphash.md +150 -0
  116. arg2p/jre/legal/java.base/unicode.md +103 -0
  117. arg2p/jre/legal/java.base/wepoll.md +34 -0
  118. arg2p/jre/legal/java.base/zlib.md +27 -0
  119. arg2p/jre/legal/java.logging/ADDITIONAL_LICENSE_INFO +1 -0
  120. arg2p/jre/legal/java.logging/ASSEMBLY_EXCEPTION +1 -0
  121. arg2p/jre/legal/java.logging/LICENSE +1 -0
  122. arg2p/jre/legal/java.management/ADDITIONAL_LICENSE_INFO +1 -0
  123. arg2p/jre/legal/java.management/ASSEMBLY_EXCEPTION +1 -0
  124. arg2p/jre/legal/java.management/LICENSE +1 -0
  125. arg2p/jre/legal/java.naming/ADDITIONAL_LICENSE_INFO +1 -0
  126. arg2p/jre/legal/java.naming/ASSEMBLY_EXCEPTION +1 -0
  127. arg2p/jre/legal/java.naming/LICENSE +1 -0
  128. arg2p/jre/legal/java.net.http/ADDITIONAL_LICENSE_INFO +1 -0
  129. arg2p/jre/legal/java.net.http/ASSEMBLY_EXCEPTION +1 -0
  130. arg2p/jre/legal/java.net.http/LICENSE +1 -0
  131. arg2p/jre/legal/java.security.sasl/ADDITIONAL_LICENSE_INFO +1 -0
  132. arg2p/jre/legal/java.security.sasl/ASSEMBLY_EXCEPTION +1 -0
  133. arg2p/jre/legal/java.security.sasl/LICENSE +1 -0
  134. arg2p/jre/legal/java.xml/ADDITIONAL_LICENSE_INFO +1 -0
  135. arg2p/jre/legal/java.xml/ASSEMBLY_EXCEPTION +1 -0
  136. arg2p/jre/legal/java.xml/LICENSE +1 -0
  137. arg2p/jre/legal/java.xml/bcel.md +219 -0
  138. arg2p/jre/legal/java.xml/dom.md +77 -0
  139. arg2p/jre/legal/java.xml/jcup.md +31 -0
  140. arg2p/jre/legal/java.xml/xalan.md +255 -0
  141. arg2p/jre/legal/java.xml/xerces.md +229 -0
  142. arg2p/jre/legal/jdk.crypto.ec/ADDITIONAL_LICENSE_INFO +1 -0
  143. arg2p/jre/legal/jdk.crypto.ec/ASSEMBLY_EXCEPTION +1 -0
  144. arg2p/jre/legal/jdk.crypto.ec/LICENSE +1 -0
  145. arg2p/jre/legal/jdk.unsupported/ADDITIONAL_LICENSE_INFO +1 -0
  146. arg2p/jre/legal/jdk.unsupported/ASSEMBLY_EXCEPTION +1 -0
  147. arg2p/jre/legal/jdk.unsupported/LICENSE +1 -0
  148. arg2p/jre/lib/classlist +1503 -0
  149. arg2p/jre/lib/jrt-fs.jar +0 -0
  150. arg2p/jre/lib/jvm.cfg +2 -0
  151. arg2p/jre/lib/jvm.lib +0 -0
  152. arg2p/jre/lib/modules +0 -0
  153. arg2p/jre/lib/security/blocked.certs +39 -0
  154. arg2p/jre/lib/security/cacerts +0 -0
  155. arg2p/jre/lib/security/default.policy +251 -0
  156. arg2p/jre/lib/security/public_suffix_list.dat +0 -0
  157. arg2p/jre/lib/tzdb.dat +0 -0
  158. arg2p/jre/lib/tzmappings +506 -0
  159. arg2p/jre/release +2 -0
  160. arg2p/model.py +102 -0
  161. arg2p/parallel.py +160 -0
  162. arg2p/py.typed +0 -0
  163. arg2p/values.py +59 -0
  164. arg2p-0.19.0.dist-info/METADATA +61 -0
  165. arg2p-0.19.0.dist-info/RECORD +168 -0
  166. arg2p-0.19.0.dist-info/WHEEL +5 -0
  167. arg2p-0.19.0.dist-info/entry_points.txt +2 -0
  168. arg2p-0.19.0.dist-info/top_level.txt +1 -0
arg2p/__init__.py ADDED
@@ -0,0 +1,63 @@
1
+ """
2
+ Arg2P from Python: structured argumentation in Prolog (ASPIC+, ABA, abstract frameworks, ...), the library of the JVM
3
+ run through JPype, on the Java runtime the package bundles.
4
+
5
+ >>> from arg2p import Arg2p
6
+ >>> Arg2p.of("r1 : [] => a.\nr2 : [] => -a.\nsup(r1, r2).").answer("a").in_statements
7
+ ['a']
8
+ """
9
+
10
+ from .arg2p import Answer, Arg2p, Arg2pError, Builder, Causality, Solution, Solutions
11
+ from .flags import (
12
+ ConflictModel,
13
+ Flags,
14
+ GraphBuilder,
15
+ GraphExtension,
16
+ GraphLanguage,
17
+ OrderingComparator,
18
+ OrderingPrinciple,
19
+ Profile,
20
+ Semantics,
21
+ StatementLabelling,
22
+ )
23
+ from .model import Argument, Attack, Graph, LabelledArgument, Support
24
+ from .parallel import EvaluationResponse, LocalCluster, Response, ThreadedCluster
25
+ from .values import Struct, Value, Var
26
+
27
+ try:
28
+ from ._version import __version__
29
+ except ImportError: # a package built without Gradle
30
+ __version__ = "0.0.0"
31
+
32
+ __all__ = [
33
+ "Answer",
34
+ "Arg2p",
35
+ "Arg2pError",
36
+ "Argument",
37
+ "Attack",
38
+ "Builder",
39
+ "Causality",
40
+ "ConflictModel",
41
+ "EvaluationResponse",
42
+ "Flags",
43
+ "Graph",
44
+ "GraphBuilder",
45
+ "GraphExtension",
46
+ "GraphLanguage",
47
+ "LabelledArgument",
48
+ "LocalCluster",
49
+ "OrderingComparator",
50
+ "OrderingPrinciple",
51
+ "Profile",
52
+ "Response",
53
+ "Semantics",
54
+ "Solution",
55
+ "Solutions",
56
+ "StatementLabelling",
57
+ "Struct",
58
+ "Support",
59
+ "ThreadedCluster",
60
+ "Value",
61
+ "Var",
62
+ "__version__",
63
+ ]
arg2p/__main__.py ADDED
@@ -0,0 +1,49 @@
1
+ """The labels of the statements of a theory, from the command line: python -m arg2p theory.pl [-q query] ..."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import sys
7
+ from typing import Optional
8
+
9
+ from .arg2p import Arg2p, Arg2pError
10
+ from .flags import Flags, Profile, Semantics
11
+ from .values import text
12
+
13
+
14
+ def main(argv: Optional[list[str]] = None) -> int:
15
+ parser = argparse.ArgumentParser(prog="arg2p", description="Evaluates a theory of arg2p.")
16
+ parser.add_argument("theory", help="the file of the theory (- for the standard input)")
17
+ parser.add_argument("-q", "--query", action="append", help="a statement to evaluate (all of them by default)")
18
+ parser.add_argument("-p", "--profile", choices=[it.value for it in Profile], help="the profile of the theory")
19
+ parser.add_argument("-s", "--semantics", choices=[it.value for it in Semantics], help="the semantics")
20
+ arguments = parser.parse_args(argv)
21
+ theory = sys.stdin.read() if arguments.theory == "-" else open(arguments.theory, encoding="utf-8").read()
22
+ flags = Flags.defaults()
23
+ if arguments.profile:
24
+ flags.graph_build_mode(Profile(arguments.profile))
25
+ if arguments.semantics:
26
+ flags.argument_labelling_mode(Semantics(arguments.semantics))
27
+ try:
28
+ arg2p = Arg2p.of(theory, flags)
29
+ if arguments.query:
30
+ for query in arguments.query:
31
+ answer = arg2p.answer(query)
32
+ print(
33
+ f"{query}: in {text(answer.in_statements)}, out {text(answer.out_statements)}, "
34
+ f"und {text(answer.und_statements)}"
35
+ )
36
+ else:
37
+ for index, graph in enumerate(arg2p.graphs()):
38
+ if index:
39
+ print()
40
+ for label in ("in", "out", "und"):
41
+ print(f"{label}: {', '.join(sorted(graph.conclusions(label)))}")
42
+ except Arg2pError as error:
43
+ print(f"arg2p: {error}", file=sys.stderr)
44
+ return 1
45
+ return 0
46
+
47
+
48
+ if __name__ == "__main__":
49
+ sys.exit(main())
arg2p/_jvm.py ADDED
@@ -0,0 +1,145 @@
1
+ """The JVM running arg2p: started once, at the first use, with the jars of the package, on the Java runtime it
2
+ bundles (that of the system, for a package without one)."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import glob
7
+ import os
8
+ import sys
9
+ import threading
10
+ from typing import Any, Callable, TypeVar
11
+
12
+ import jpype
13
+
14
+ T = TypeVar("T")
15
+
16
+ _lock = threading.Lock()
17
+
18
+ #: The jars of the package, copied there by ``./gradlew :python:pythonJars``
19
+ JARS = os.path.join(os.path.dirname(__file__), "jars")
20
+
21
+ #: The Java runtime the package bundles, made there by ``./gradlew :python:pythonRuntime``
22
+ RUNTIME = os.path.join(os.path.dirname(__file__), "jre")
23
+
24
+ #: The stack of the threads of the JVM: resolution goes deep (the tests of arg2p run with the same)
25
+ STACK = os.environ.get("ARG2P_STACK", "512m")
26
+
27
+
28
+ def classpath() -> list[str]:
29
+ """The jars of arg2p: those of ``ARG2P_CLASSPATH`` if set, those of the package otherwise."""
30
+ stated = os.environ.get("ARG2P_CLASSPATH")
31
+ if stated:
32
+ return stated.split(os.pathsep)
33
+ jars = sorted(glob.glob(os.path.join(JARS, "*.jar")))
34
+ if not jars:
35
+ raise RuntimeError(
36
+ "No jar of arg2p in " + JARS + ": copy them with ./gradlew :python:pythonJars, "
37
+ "or set ARG2P_CLASSPATH"
38
+ )
39
+ return jars
40
+
41
+
42
+ def jvm_path() -> str:
43
+ """
44
+ The library of the JVM: that of ``ARG2P_JVM`` if set, of the runtime the package bundles if it does, of the system
45
+ otherwise (JAVA_HOME, or where JPype finds one).
46
+ """
47
+ stated = os.environ.get("ARG2P_JVM")
48
+ if stated:
49
+ return stated
50
+ library = {"win32": ("bin", "server", "jvm.dll"), "darwin": ("lib", "server", "libjvm.dylib")}.get(
51
+ sys.platform, ("lib", "server", "libjvm.so")
52
+ )
53
+ bundled = os.path.join(RUNTIME, *library)
54
+ return bundled if os.path.exists(bundled) else jpype.getDefaultJVMPath()
55
+
56
+
57
+ def start() -> None:
58
+ """Starts the JVM, unless it runs already (started by another library: the jars of arg2p must be on its path)."""
59
+ with _lock:
60
+ if not jpype.isJVMStarted():
61
+ jpype.startJVM(
62
+ jvm_path(), f"-Xss{STACK}", "-Dslf4j.internal.verbosity=ERROR", classpath=classpath(), convertStrings=True
63
+ )
64
+
65
+
66
+ def jclass(name: str) -> Any:
67
+ """The Java class [name], the JVM started."""
68
+ start()
69
+ return jpype.JClass(name)
70
+
71
+
72
+ @jpype.JImplements("java.lang.Runnable", deferred=True)
73
+ class _Task:
74
+ def __init__(self, function: Callable[[], Any]) -> None:
75
+ self.function = function
76
+ self.value: Any = None
77
+ self.error: BaseException | None = None
78
+
79
+ @jpype.JOverride
80
+ def run(self) -> None:
81
+ try:
82
+ self.value = self.function()
83
+ except BaseException as error: # noqa: BLE001 - raised again by the caller
84
+ self.error = error
85
+
86
+
87
+ @jpype.JImplements("java.util.concurrent.ThreadFactory", deferred=True)
88
+ class _Threads:
89
+ @jpype.JOverride
90
+ def newThread(self, runnable: Any) -> Any:
91
+ # daemons, not to hold the JVM when Python exits; their stack is the one of -Xss (see STACK)
92
+ thread = jpype.JClass("java.lang.Thread")(runnable, _THREAD)
93
+ thread.setDaemon(True)
94
+ return thread
95
+
96
+
97
+ _THREAD = "arg2p"
98
+ _pool: Any = None
99
+
100
+
101
+ def _threads() -> Any:
102
+ """The threads running arg2p, made as calls need them and kept for the next ones (a minute idle)."""
103
+ global _pool
104
+ with _lock:
105
+ if _pool is None:
106
+ _pool = jpype.JClass("java.util.concurrent.Executors").newCachedThreadPool(_Threads())
107
+ return _pool
108
+
109
+
110
+ def run(function: Callable[[], T]) -> T:
111
+ """The result of [function], run on a thread of the JVM, whose stack resolution needs (see STACK)."""
112
+ start()
113
+ if str(jpype.JClass("java.lang.Thread").currentThread().getName()) == _THREAD:
114
+ return function() # already on one
115
+ task = _Task(function)
116
+ _threads().submit(task).get()
117
+ if task.error is not None:
118
+ raise task.error
119
+ return task.value
120
+
121
+
122
+ @jpype.JImplements("kotlin.jvm.functions.Function1", deferred=True)
123
+ class _Function:
124
+ def __init__(self, function: Callable[[Any], Any]) -> None:
125
+ self.function = function
126
+
127
+ @jpype.JOverride
128
+ def invoke(self, value: Any) -> Any:
129
+ return self.function(value)
130
+
131
+
132
+ def function1(function: Callable[[Any], Any]) -> Any:
133
+ """[function] as a Kotlin function of one argument returning Unit."""
134
+ unit = jclass("kotlin.Unit").INSTANCE
135
+
136
+ def invoke(value: Any) -> Any:
137
+ function(value)
138
+ return unit
139
+
140
+ return _Function(invoke)
141
+
142
+
143
+ def jarray(name: str, values: list[Any]) -> Any:
144
+ """A Java array of the class [name], of [values]."""
145
+ return jpype.JArray(jclass(name))(values)
arg2p/_version.py ADDED
@@ -0,0 +1,2 @@
1
+ # Generated by the build (./gradlew :python:pythonVersion): the version of arg2p
2
+ __version__ = "0.19.0"
arg2p/arg2p.py ADDED
@@ -0,0 +1,271 @@
1
+ """A solver of arg2p: its answers, graphs and solutions, and the causality tests on its theory."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any, Callable, Iterator, Optional
7
+
8
+ import jpype
9
+
10
+ from . import _jvm
11
+ from .flags import Flags
12
+ from .model import Graph, graph_from_jvm
13
+ from .values import Value, from_jvm
14
+
15
+ _API = "it.unibo.tuprolog.argumentation"
16
+
17
+
18
+ class Arg2pError(Exception):
19
+ """An evaluation halted by an error: a theory its profile refuses, a goal that cannot be parsed, ..."""
20
+
21
+
22
+ def call(function: Callable[[], Any]) -> Any:
23
+ """The result of [function], run on a thread of the JVM, an exception of arg2p raised as an Arg2pError."""
24
+
25
+ def guarded() -> Any:
26
+ try:
27
+ return function()
28
+ except jpype.JException as error:
29
+ if error.getClass().getName() == f"{_API}.Arg2pException":
30
+ raise Arg2pError(str(error.getMessage())) from None
31
+ raise
32
+
33
+ return _jvm.run(guarded)
34
+
35
+
36
+ @dataclass(frozen=True)
37
+ class Answer:
38
+ """The statements for a query labelled in, out and und (see Arg2p.answer)."""
39
+
40
+ in_statements: list[Value] = field(default_factory=list)
41
+ out_statements: list[Value] = field(default_factory=list)
42
+ und_statements: list[Value] = field(default_factory=list)
43
+ # the answer of the library of the JVM, for label
44
+ _answer: Any = field(default=None, compare=False, repr=False)
45
+
46
+ def label(self, statement: str) -> Optional[str]:
47
+ """The label of [statement], Prolog text: in, out or und, None for a statement the query did not label."""
48
+ if self._answer is None:
49
+ raise ValueError("Not the answer of a solver")
50
+ label = call(lambda: self._answer.label(statement))
51
+ return None if label is None else str(label)
52
+
53
+
54
+ class Solution:
55
+ """A solution of a goal: yes, no or halt (an error), with the values a yes solution binds to its variables."""
56
+
57
+ def __init__(self, solution: Any) -> None:
58
+ self._solution = solution
59
+
60
+ @property
61
+ def is_yes(self) -> bool:
62
+ return bool(self._solution.isYes())
63
+
64
+ @property
65
+ def is_no(self) -> bool:
66
+ return bool(self._solution.isNo())
67
+
68
+ @property
69
+ def is_halt(self) -> bool:
70
+ return bool(self._solution.isHalt())
71
+
72
+ @property
73
+ def query(self) -> str:
74
+ """The goal, as a yes solution solves it (its variables bound), otherwise as it was asked, as Prolog text."""
75
+ return str(self._solution.getQuery())
76
+
77
+ @property
78
+ def error(self) -> Optional[str]:
79
+ """The error of a halt solution."""
80
+ error = self._solution.getError()
81
+ return None if error is None else str(error)
82
+
83
+ @property
84
+ def variables(self) -> list[str]:
85
+ """The variables of the goal a yes solution binds."""
86
+ return [str(name) for name in self._solution.getVariables()]
87
+
88
+ @property
89
+ def bindings(self) -> dict[str, Value]:
90
+ """The values a yes solution binds to the variables of the goal, by their names."""
91
+ return {str(entry.getKey()): from_jvm(entry.getValue()) for entry in self._solution.getBindings().entrySet()}
92
+
93
+ def value(self, name: str) -> Optional[Value]:
94
+ """The value a yes solution binds to the variable of the goal named [name]."""
95
+ value = self._solution.value(name)
96
+ return None if value is None else from_jvm(value)
97
+
98
+ def text(self, name: str) -> Optional[str]:
99
+ """The value a yes solution binds to the variable of the goal named [name], as Prolog text."""
100
+ written = self._solution.text(name)
101
+ return None if written is None else str(written)
102
+
103
+ def __repr__(self) -> str:
104
+ return str(self._solution.toString())
105
+
106
+
107
+ class Solutions:
108
+ """The solutions of a goal, computed one at a time as they are asked for: with has_next and next, or iterated."""
109
+
110
+ def __init__(self, solutions: Any) -> None:
111
+ self._solutions = solutions
112
+
113
+ def has_next(self) -> bool:
114
+ return bool(_jvm.run(self._solutions.hasNext))
115
+
116
+ def next(self) -> Solution:
117
+ return Solution(_jvm.run(self._solutions.next))
118
+
119
+ def to_list(self, limit: Optional[int] = None) -> list[Solution]:
120
+ """The solutions left, at most [limit] of them."""
121
+ return [Solution(it) for it in _jvm.run(lambda: self._solutions.toList(2**31 - 1 if limit is None else limit))]
122
+
123
+ def __iter__(self) -> Iterator[Solution]:
124
+ return self
125
+
126
+ def __next__(self) -> Solution:
127
+ # the next solution, if there is one, in a single call
128
+ found = _jvm.run(lambda: self._solutions.next() if self._solutions.hasNext() else None)
129
+ if found is None:
130
+ raise StopIteration
131
+ return Solution(found)
132
+
133
+
134
+ class Causality:
135
+ """
136
+ Whether a statement of the theory of a solver causes another, on the grounded labelling of the theory and of its
137
+ interventions: the NESS test, as published (Pisano, Prakken, Sartor, Liepina; ICAIL 2025) and revised, and the
138
+ but-for test. The statements are Prolog text; an intervention is a list of statements.
139
+ """
140
+
141
+ def __init__(self, causality: Any) -> None:
142
+ self._causality = causality
143
+
144
+ def ness(self, cause: str, effect: str) -> Optional[Value]:
145
+ """Whether [cause] is a NESS cause of [effect] (the revised condition): the intervention, None if it is not."""
146
+ return _optional(call(lambda: self._causality.ness(cause, effect)))
147
+
148
+ def ness_original(self, cause: str, effect: str) -> Optional[Value]:
149
+ """Whether [cause] is a NESS cause of [effect] as published: the intervention, None if it is not."""
150
+ return _optional(call(lambda: self._causality.nessOriginal(cause, effect)))
151
+
152
+ def ness_intervention(self, intervention: str, effect: str) -> bool:
153
+ """Whether [intervention], a list of statements, meets the revised NESS condition for [effect]."""
154
+ return bool(call(lambda: self._causality.nessIntervention(intervention, effect)))
155
+
156
+ def ness_original_intervention(self, intervention: str, effect: str) -> bool:
157
+ """Whether [intervention], a list of statements, meets the NESS condition for [effect] as published."""
158
+ return bool(call(lambda: self._causality.nessOriginalIntervention(intervention, effect)))
159
+
160
+ def but_for(self, cause: str, effect: str) -> bool:
161
+ """Whether [cause] is a but-for cause of [effect]."""
162
+ return bool(call(lambda: self._causality.butFor(cause, effect)))
163
+
164
+
165
+ def _optional(value: Any) -> Optional[Value]:
166
+ return None if value is None else from_jvm(value)
167
+
168
+
169
+ class Arg2p:
170
+ """
171
+ A solver of arg2p for a theory, as Prolog text, with its flags: it answers queries (answer), gives the graph of
172
+ each labelling (graphs), solves Prolog goals (solve) and tests causality (causality).
173
+
174
+ >>> Arg2p.of("r1 : [] => a.\\nr2 : [] => -a.\\nsup(r1, r2).").answer("a").in_statements
175
+ ['a']
176
+
177
+ The context of the solver keeps a branch for every stage of a resolution, numbered from 0: active_branch is the
178
+ last one, graph_at the graph of any of them, and context_facts what a branch stores.
179
+ """
180
+
181
+ def __init__(self, arg2p: Any) -> None:
182
+ self._arg2p = arg2p
183
+ self.causality = Causality(arg2p.getCausality())
184
+
185
+ @staticmethod
186
+ def of(theory: str = "", flags: Optional[Flags] = None) -> Arg2p:
187
+ """A solver of arg2p for [theory], Prolog text, with [flags] (Flags.defaults() otherwise)."""
188
+ return Arg2p.builder().theory(theory).flags(flags or Flags.defaults()).build()
189
+
190
+ @staticmethod
191
+ def builder() -> Builder:
192
+ """A solver of arg2p, as it is described."""
193
+ return Builder()
194
+
195
+ @staticmethod
196
+ def version() -> str:
197
+ """The version of arg2p, the released one for a release."""
198
+ return str(_jvm.jclass(f"{_API}.Arg2p").version())
199
+
200
+ @property
201
+ def theory(self) -> str:
202
+ """The theory, as Prolog text."""
203
+ return str(self._arg2p.getTheory())
204
+
205
+ def answer(self, query: str) -> Answer:
206
+ """The statements for [query], Prolog text, labelled in, out and und (raises Arg2pError if it halts)."""
207
+ answer = call(lambda: self._arg2p.answer(query))
208
+ return Answer(
209
+ [from_jvm(it) for it in answer.getInStatements()],
210
+ [from_jvm(it) for it in answer.getOutStatements()],
211
+ [from_jvm(it) for it in answer.getUndStatements()],
212
+ answer,
213
+ )
214
+
215
+ def graphs(self) -> list[Graph]:
216
+ """The graph of each labelling of the theory: several for a semantics with several (preferred, stable, ...)."""
217
+ return call(lambda: [graph_from_jvm(graph) for graph in self._arg2p.graphs()])
218
+
219
+ def graph(self) -> Graph:
220
+ """The graph of the last resolution: the one of its last stage."""
221
+ return call(lambda: graph_from_jvm(self._arg2p.graph()))
222
+
223
+ def graph_at(self, branch: int) -> Graph:
224
+ """The graph of the context branch [branch]."""
225
+ return call(lambda: graph_from_jvm(self._arg2p.graphAt(branch)))
226
+
227
+ @property
228
+ def active_branch(self) -> int:
229
+ """The context branch of the last stage of the last resolution."""
230
+ return int(call(self._arg2p.getActiveBranch))
231
+
232
+ def solve(self, goal: str) -> Solutions:
233
+ """The solutions of [goal], Prolog text, computed one at a time as they are asked for."""
234
+ return Solutions(call(lambda: self._arg2p.solve(goal)))
235
+
236
+ def context_facts(self, branch: int, goal: str) -> Solutions:
237
+ """What the context branch [branch] stores matching [goal], Prolog text: the solutions of context_check/2."""
238
+ return Solutions(call(lambda: self._arg2p.contextFacts(branch, goal)))
239
+
240
+ def add(self, theory: str) -> None:
241
+ """Adds the clauses of [theory], Prolog text, to the theory."""
242
+ call(lambda: self._arg2p.add(theory))
243
+
244
+ def load(self, theory: str) -> None:
245
+ """Replaces the theory with [theory], Prolog text."""
246
+ call(lambda: self._arg2p.load(theory))
247
+
248
+
249
+ class Builder:
250
+ """A solver of arg2p, as it is described: its theory, its flags, and where what it prints goes."""
251
+
252
+ def __init__(self) -> None:
253
+ self._builder = _jvm.jclass(f"{_API}.Arg2p").builder()
254
+
255
+ def theory(self, theory: str) -> Builder:
256
+ """The theory, as Prolog text."""
257
+ self._builder.theory(theory)
258
+ return self
259
+
260
+ def flags(self, flags: Flags) -> Builder:
261
+ """The flags (Flags.defaults() otherwise)."""
262
+ self._builder.flags(flags.jvm())
263
+ return self
264
+
265
+ def output(self, consumer: Callable[[str], Any]) -> Builder:
266
+ """The function receiving what the solver prints (the standard output otherwise)."""
267
+ self._builder.output(_jvm.function1(lambda printed: consumer(str(printed))))
268
+ return self
269
+
270
+ def build(self) -> Arg2p:
271
+ return Arg2p(call(self._builder.build))