diff --git a/.gitignore b/.gitignore
index 3dc4d04..dbfde15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -135,3 +135,8 @@ dmypy.json
.idea/
.vscode/
+
+# explainer Stuff
+explainer/test.py
+explainer/old_code.py
+tutorial/conf.py
diff --git a/bpmnconstraints/compiler/bpmn_compiler.py b/bpmnconstraints/compiler/bpmn_compiler.py
index 43b802d..276ad86 100644
--- a/bpmnconstraints/compiler/bpmn_compiler.py
+++ b/bpmnconstraints/compiler/bpmn_compiler.py
@@ -43,7 +43,7 @@ def __compile(self):
self.__create_response_constraint()
def _create_gateway_constraints(self):
- if self.__get_cfo_type() == XOR_GATEWAY:
+ if self.__get_cfo_type() in XOR_GATEWAY:
self.__create_exclusive_choice_constraint()
if self.__get_cfo_type() == AND_GATEWAY:
diff --git a/bpmnconstraints/parser/bpmn_parser.py b/bpmnconstraints/parser/bpmn_parser.py
index a61c6ee..b6b6982 100644
--- a/bpmnconstraints/parser/bpmn_parser.py
+++ b/bpmnconstraints/parser/bpmn_parser.py
@@ -73,11 +73,13 @@ def validate_splitting_and_joining_gateway_cases(self):
item_indices = {item["name"]: index for index, item in enumerate(self.sequence)}
for cfo in self.sequence:
- if cfo["is start"] and cfo["name"] == "XOR":
+ if cfo["is start"] and (cfo["type"] in DISCARDED_START_GATEWAYS):
cfo["is start"] = False
for successor in cfo["successor"]:
self.sequence[item_indices[successor["name"]]]["is start"] = True
- if cfo["is end"] and cfo["name"] in GATEWAY_NAMES:
+ if cfo["is end"] and (
+ cfo["name"] in GATEWAY_NAMES or cfo["type"] == "exclusivegateway"
+ ):
cfo["is end"] = False
for predecessor in cfo["predecessor"]:
self.sequence[item_indices[predecessor["name"]]]["is end"] = True
diff --git a/bpmnconstraints/parser/xml_model.py b/bpmnconstraints/parser/xml_model.py
index 48a157f..a6243e8 100644
--- a/bpmnconstraints/parser/xml_model.py
+++ b/bpmnconstraints/parser/xml_model.py
@@ -22,7 +22,10 @@ def __xml_to_dict(self, input_dict):
if key.startswith("@"):
new_dict[key[1:]] = value
elif key.endswith(":outgoing"):
- new_dict["outgoing"].append(value)
+ if isinstance(value, list):
+ new_dict["outgoing"].extend(value)
+ else:
+ new_dict["outgoing"].append(value)
else:
new_dict[key] = value
return new_dict
diff --git a/bpmnconstraints/script.py b/bpmnconstraints/script.py
index 6f7eb1e..060ca00 100644
--- a/bpmnconstraints/script.py
+++ b/bpmnconstraints/script.py
@@ -1,4 +1,5 @@
"""Entry point for bpmnsignal command. Verifies argument and runs parser."""
+
# pylint: disable=import-error
import argparse
import logging
diff --git a/bpmnconstraints/utils/constants.py b/bpmnconstraints/utils/constants.py
index 6ad8448..826da42 100644
--- a/bpmnconstraints/utils/constants.py
+++ b/bpmnconstraints/utils/constants.py
@@ -9,6 +9,8 @@
"exclusivegateway",
]
+DISCARDED_START_GATEWAYS = ["exclusive_databased_gateway", "exclusivegateway"]
+
ALLOWED_ACTIVITIES = [
"task",
"event",
@@ -148,7 +150,7 @@
"OR",
]
-XOR_GATEWAY = "exclusive_databased_gateway"
+XOR_GATEWAY = ["exclusive_databased_gateway", "exclusivegateway"]
AND_GATEWAY = "parallelgateway"
OR_GATEWAY = "inclusivegateway"
diff --git a/bpmnconstraints/utils/plot.py b/bpmnconstraints/utils/plot.py
index 7a5990c..434b782 100644
--- a/bpmnconstraints/utils/plot.py
+++ b/bpmnconstraints/utils/plot.py
@@ -1,6 +1,7 @@
"""
Module for plotting functions.
"""
+
# pylint: disable=import-error
import matplotlib.pyplot as plt
diff --git a/examples/advanced/student_project.xml b/examples/advanced/student_project.xml
new file mode 100644
index 0000000..9ec4256
--- /dev/null
+++ b/examples/advanced/student_project.xml
@@ -0,0 +1,844 @@
+
+
+
+
+
+
+
+
+
+ /glossary/7b44f64199404855bc9c473bece4b616
+
+
+
+
+
+
+
+
+
+ /glossary/4283363449cf469a8b9e959d9f7a280a
+
+
+
+
+
+
+
+ /glossary/8a1ce45019234067b57f0f007bd4d3e1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-E96C109E-D90B-4069-9743-1501AFDE2AA9
+ sid-032F0C1F-E53B-4B23-8943-4FD5C5DD8BD5
+ sid-C209D0BF-109F-428C-AD0F-3518B68DBE16
+ sid-FF08099D-4C6E-4AEF-A9DE-AA0CEF759E0E
+ sid-4ACD99D6-5FE6-4071-862A-6D4A5FDFCB7D
+ sid-87F4AE1D-1626-4284-BDF0-0E63BFFB1876
+ sid-407C128E-1AD6-4058-9979-7E907598B432
+ sid-022CFEC4-F6CE-4F90-BC76-B3B73E85A049
+ sid-0DBDC4E5-F5E9-4671-837C-BFFADC7054A9
+
+
+
+
+
+
+
+
+ sid-39C5D9F6-1A07-4355-BC65-9ACAE410B74D
+
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+
+ sid-39C5D9F6-1A07-4355-BC65-9ACAE410B74D
+ sid-E69D3C89-0103-4BE5-A8DC-A733784F8A71
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-E7F39E5C-FDB0-49BB-8DB1-1AC7978EE079
+ sid-8B2D0A24-64A6-41FA-901A-AD06E9A8B35E
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-8B2D0A24-64A6-41FA-901A-AD06E9A8B35E
+ sid-59FF3545-132C-48ED-BE7D-3F1A3D7CBA72
+
+
+
+
+
+
+
+ sid-59FF3545-132C-48ED-BE7D-3F1A3D7CBA72
+ sid-1719017A-FD02-4DDE-A3AE-844423E417EF
+
+
+
+ sid-60eda481-b41b-4bb7-83c9-5ac3b2454794
+ sid-85e5fba0-550d-47e3-be50-a20dd4c68f50
+
+
+ sid-a3568e12-f90c-4271-95c4-debc02432f93
+
+
+
+
+
+
+ sid-23BAF1C8-0567-4C21-8EA5-E78AA65B2B3E
+ sid-60eda481-b41b-4bb7-83c9-5ac3b2454794
+
+
+
+
+
+
+
+ sid-BC06A9A6-DDFC-4ABD-A903-F5DB38FD2CE2
+ sid-D74FB0C0-366E-4E30-98D7-A80E8B6DB13C
+ sid-5ADDD38C-B160-4F84-8CDD-B415381E3994
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-80AB97B6-BBE3-41B4-B486-917AD1D8E3B6
+ sid-68E2FD87-C7A6-4AF5-9452-6C36F8B66910
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-8F5F3226-DADE-425E-8F02-7D66BB70B315
+ sid-80AB97B6-BBE3-41B4-B486-917AD1D8E3B6
+
+
+
+
+
+
+ sid-68E2FD87-C7A6-4AF5-9452-6C36F8B66910
+ sid-B3922F8A-2BC1-4321-8AA7-AC4808B0017C
+
+
+
+
+
+
+
+
+ sid-B3922F8A-2BC1-4321-8AA7-AC4808B0017C
+ sid-E9536DC1-D869-4B69-9BAF-30D2DBC7299A
+ sid-4A10F79E-813F-46D3-BE19-AA09C730648D
+
+
+
+
+
+
+ sid-4A10F79E-813F-46D3-BE19-AA09C730648D
+ sid-CF562066-8973-4CBC-A274-0955EF9E5621
+ sid-8F5F3226-DADE-425E-8F02-7D66BB70B315
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-E9536DC1-D869-4B69-9BAF-30D2DBC7299A
+ sid-25905704-1285-48D7-BDD8-683AB4B410BA
+
+
+
+
+
+
+ sid-25905704-1285-48D7-BDD8-683AB4B410BA
+ sid-707CCF34-350E-4B61-949A-D5A1871A785F
+ sid-CC058DA2-7867-4C22-81A5-31B5367396F6
+
+
+
+
+
+
+
+ sid-707CCF34-350E-4B61-949A-D5A1871A785F
+ sid-9F23170C-E001-4361-97F0-16723E82FC74
+
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-9F23170C-E001-4361-97F0-16723E82FC74
+ sid-D74FB0C0-366E-4E30-98D7-A80E8B6DB13C
+
+
+
+
+
+
+
+ sid-CC058DA2-7867-4C22-81A5-31B5367396F6
+ sid-BC06A9A6-DDFC-4ABD-A903-F5DB38FD2CE2
+
+
+
+
+
+
+
+ sid-CF562066-8973-4CBC-A274-0955EF9E5621
+
+
+
+
+
+
+ sid-5ADDD38C-B160-4F84-8CDD-B415381E3994
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-1719017A-FD02-4DDE-A3AE-844423E417EF
+
+
+
+
+
+
+ sid-E69D3C89-0103-4BE5-A8DC-A733784F8A71
+ sid-75BBE3A6-E70A-4241-8404-8DCB1EACF757
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-8E304810-00A4-44EB-8FC2-EAE4A9372542
+
+
+
+
+
+
+ sid-8E304810-00A4-44EB-8FC2-EAE4A9372542
+ sid-D34CB892-73FE-487F-919E-DF1CFF7EB509
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-D34CB892-73FE-487F-919E-DF1CFF7EB509
+
+
+
+ sid-ae718694-8d3e-47e4-a043-77d7393977a1
+
+
+ sid-d604e796-1eec-4e2b-bf3e-d414001c7784
+ sid-eb8a804a-033d-4900-8cbb-e953a2a77244
+
+
+
+
+
+
+ sid-d604e796-1eec-4e2b-bf3e-d414001c7784
+ sid-23BAF1C8-0567-4C21-8EA5-E78AA65B2B3E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-75BBE3A6-E70A-4241-8404-8DCB1EACF757
+ sid-0256DDFA-1400-4FB8-B163-88C87D72FCD5
+ sid-E7F39E5C-FDB0-49BB-8DB1-1AC7978EE079
+
+
+ sid-0256DDFA-1400-4FB8-B163-88C87D72FCD5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/advanced/underwriter.xml b/examples/advanced/underwriter.xml
new file mode 100644
index 0000000..7bb79e0
--- /dev/null
+++ b/examples/advanced/underwriter.xml
@@ -0,0 +1,508 @@
+
+
+
+
+
+
+
+
+
+ /glossary/7d71dfb4d73f49c682c123c66cf76beb
+
+
+
+
+
+
+
+ /glossary/637e2bf8539443678fec17706e30d0a4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-CFAFA606-1D7C-4078-8EBB-BEF55FBC3E7D
+ sid-C8F4AFC3-9686-4C6D-8AC7-F74246E980FB
+ sid-34AA0C14-41DF-406C-B467-8BE3D376AFE8
+ sid-D6C50FE5-E074-4360-991E-F6B88149A1AC
+ sid-4209DA92-1208-4121-ACB6-C4D7EDF378C3
+ sid-4D681FF5-23AA-46EE-8939-68658FDB1B9E
+ sid-7E2F5F04-D4D5-407B-A20A-CA124DC33721
+ sid-62605252-413E-4A89-8F9E-7072F6D33513
+ sid-A44D6075-6BAA-4E1F-8BD2-DEBE46F95DF7
+ sid-249C44C7-5400-4E15-B639-079545722FD8
+ sid-23133592-3711-47A0-82CA-48D54157DFBF
+ sid-A5B13FE9-2224-4505-91A3-C04C28BEFBAE
+ sid-C590C471-743B-47C8-9F56-328A5FE36F36
+ sid-BF161723-6B96-46C1-8747-6A663E0932B3
+ sid-ABADA803-AC9B-41C0-8DF6-E3D1FFC09BAD
+
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+
+ sid-AD7E1C74-7100-4517-982E-B38FC9D21599
+ sid-A2070167-1F01-4F48-96BE-FAE6BF54FF51
+
+
+
+
+
+
+ sid-A43778C4-BE9F-481F-B964-61CF35C39E3B
+ sid-AD7E1C74-7100-4517-982E-B38FC9D21599
+ sid-A89695D9-614D-4FD6-BEC4-F4C64E67454E
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-A89695D9-614D-4FD6-BEC4-F4C64E67454E
+ sid-9A816B75-E97B-4E65-B7EF-BAE3050E14E6
+
+
+
+
+
+
+ sid-9A816B75-E97B-4E65-B7EF-BAE3050E14E6
+ sid-A2070167-1F01-4F48-96BE-FAE6BF54FF51
+ sid-DD637621-8C88-4A5B-8707-245B25F87838
+
+
+
+
+
+
+ sid-DD637621-8C88-4A5B-8707-245B25F87838
+ sid-17BA13B5-6981-4226-B82D-F47C50C93ECD
+ sid-56E1C6C2-B1A9-42A4-9B08-4AACDF220D29
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-17BA13B5-6981-4226-B82D-F47C50C93ECD
+ sid-946AA84B-77EC-4061-9C77-3B0440260710
+
+
+
+
+
+
+ sid-56E1C6C2-B1A9-42A4-9B08-4AACDF220D29
+ sid-E76CBCC3-4469-4CB8-BE48-3DE18E568518
+
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-946AA84B-77EC-4061-9C77-3B0440260710
+ sid-BAE672EF-224D-4BC2-96F8-2FAACB87BA56
+
+
+
+
+
+
+ sid-BAE672EF-224D-4BC2-96F8-2FAACB87BA56
+ sid-E76CBCC3-4469-4CB8-BE48-3DE18E568518
+ sid-947FB614-CDE7-49AC-83C5-2A5F065A754C
+
+
+ In here shall be the documentation for the task.
+
+
+
+
+
+
+
+
+
+ sid-947FB614-CDE7-49AC-83C5-2A5F065A754C
+ sid-973F9DD2-3307-42D1-874A-19EA851C1833
+
+
+
+
+
+
+ sid-E1F2ACCA-397C-4704-82AD-CA331F695BC8
+
+
+
+
+
+
+
+ sid-973F9DD2-3307-42D1-874A-19EA851C1833
+ sid-6A7FD725-D38B-41A5-A840-E3BC9054C1C1
+ sid-18CA7402-927C-4946-8CAB-722E47B9BBBA
+
+
+
+
+
+
+
+
+
+
+
+ sid-6A7FD725-D38B-41A5-A840-E3BC9054C1C1
+ sid-E1F2ACCA-397C-4704-82AD-CA331F695BC8
+
+
+
+
+
+
+ sid-18CA7402-927C-4946-8CAB-722E47B9BBBA
+
+
+
+
+
+
+
+ sid-A43778C4-BE9F-481F-B964-61CF35C39E3B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SEC - Securities and Exchange Commision
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/and_gates/longer_and.xml b/examples/and_gates/longer_and.xml
new file mode 100644
index 0000000..0a4a90e
--- /dev/null
+++ b/examples/and_gates/longer_and.xml
@@ -0,0 +1,1172 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-B1919CF8-0997-44D5-BAA5-4540027E8655
+
+
+
+
+
+
+
+
+
+
+
+ sid-FAEBD832-7FC9-4CEF-9053-20F21BBD4886
+ sid-40231F2D-3243-4FB2-BE8F-0625507DA73C
+ sid-2933E377-B338-403C-9A5A-9972A120411B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-40231F2D-3243-4FB2-BE8F-0625507DA73C
+ sid-8B5FE184-C034-4CB2-B551-DAA9EE9652CD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-2933E377-B338-403C-9A5A-9972A120411B
+ sid-C5E1B14A-3E12-4664-83F0-ED4D51C74ECB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C5E1B14A-3E12-4664-83F0-ED4D51C74ECB
+ sid-AEF87569-F16C-46A0-B5B2-E8EE69F4C80C
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-AEF87569-F16C-46A0-B5B2-E8EE69F4C80C
+ sid-8F8CB7B1-66A1-4999-BFCA-5F90AD432122
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-8B5FE184-C034-4CB2-B551-DAA9EE9652CD
+ sid-9E07115D-05DF-4ED0-A6C8-ED39A3F17095
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-9E07115D-05DF-4ED0-A6C8-ED39A3F17095
+ sid-77C21B8F-898F-4CB7-B16C-270718417B59
+
+
+
+
+
+
+
+
+
+
+
+ sid-77C21B8F-898F-4CB7-B16C-270718417B59
+ sid-8F8CB7B1-66A1-4999-BFCA-5F90AD432122
+ sid-C215014A-DD4D-44C7-A465-C0F082F8291E
+
+
+
+
+
+
+
+
+
+
+
+ sid-8AF85E18-66BA-4817-9860-81BB9E0839CD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-B1919CF8-0997-44D5-BAA5-4540027E8655
+ sid-FAEBD832-7FC9-4CEF-9053-20F21BBD4886
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C215014A-DD4D-44C7-A465-C0F082F8291E
+ sid-8AF85E18-66BA-4817-9860-81BB9E0839CD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/and_gates/single_and.xml b/examples/and_gates/single_and.xml
new file mode 100644
index 0000000..4f982c1
--- /dev/null
+++ b/examples/and_gates/single_and.xml
@@ -0,0 +1,514 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-835CE72E-BA7D-4DB6-856D-48A706028690
+
+
+
+
+
+
+
+
+
+
+
+ sid-79174C7C-DDE7-4639-A718-B7EAAA904309
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-6B10282B-687D-40D9-8F9A-1B4FC29CCA26
+ sid-9CFB1B24-C587-4899-9BE0-EFE065E72B79
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-A6B93C15-E177-4CB9-8D59-8B9AF874D48F
+ sid-CA8D995D-DD3D-4DD8-BFED-0729CBF8F375
+
+
+
+
+
+
+
+
+
+
+
+ sid-835CE72E-BA7D-4DB6-856D-48A706028690
+ sid-6B10282B-687D-40D9-8F9A-1B4FC29CCA26
+ sid-A6B93C15-E177-4CB9-8D59-8B9AF874D48F
+
+
+
+
+
+
+
+
+
+
+
+ sid-CA8D995D-DD3D-4DD8-BFED-0729CBF8F375
+ sid-9CFB1B24-C587-4899-9BE0-EFE065E72B79
+ sid-79174C7C-DDE7-4639-A718-B7EAAA904309
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/combinations/nested_and_or.xml b/examples/combinations/nested_and_or.xml
new file mode 100644
index 0000000..3c0bc49
--- /dev/null
+++ b/examples/combinations/nested_and_or.xml
@@ -0,0 +1,688 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-FC368C7B-5AE7-4261-A3E6-5AC7EDDD8002
+
+
+
+
+
+
+
+
+
+
+
+ sid-FC368C7B-5AE7-4261-A3E6-5AC7EDDD8002
+ sid-79C63AA5-87CB-4095-9094-659F7724597B
+ sid-514B4958-AFEE-49A8-8176-EF033A2E3A04
+
+
+
+
+
+
+
+
+
+
+
+ sid-FE8DF871-477F-4836-9B23-BD611075487D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-79C63AA5-87CB-4095-9094-659F7724597B
+ sid-0EAAC1EE-DA8D-44FD-B4A4-95BC66AA606E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BC8D2276-041F-4E23-9506-DFB31DE51E61
+ sid-8E788ACA-FBF5-4633-8E2D-4C05EE78F031
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-248BD3B1-BF44-4994-BF85-B31249B61A3D
+ sid-85723557-4483-4C67-85E3-45CB1A6F83A7
+
+
+
+
+
+
+
+
+
+
+
+ sid-0EAAC1EE-DA8D-44FD-B4A4-95BC66AA606E
+ sid-4E6FDFD7-6BAF-44D5-85C7-B90CA038FA78
+ sid-FE8DF871-477F-4836-9B23-BD611075487D
+
+
+
+
+
+
+
+
+
+ sid-514B4958-AFEE-49A8-8176-EF033A2E3A04
+ sid-BC8D2276-041F-4E23-9506-DFB31DE51E61
+ sid-248BD3B1-BF44-4994-BF85-B31249B61A3D
+
+
+
+
+
+
+
+
+
+ sid-85723557-4483-4C67-85E3-45CB1A6F83A7
+ sid-8E788ACA-FBF5-4633-8E2D-4C05EE78F031
+ sid-4E6FDFD7-6BAF-44D5-85C7-B90CA038FA78
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/combinations/nested_and_or_xor.xml b/examples/combinations/nested_and_or_xor.xml
new file mode 100644
index 0000000..428c716
--- /dev/null
+++ b/examples/combinations/nested_and_or_xor.xml
@@ -0,0 +1,868 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-619A8AFA-5799-4B74-B0ED-0AC2A23F44B8
+
+
+
+
+
+
+
+
+
+
+
+ sid-664D038B-7B06-4DBC-A47F-2C4CEBD0A874
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-0FACBC0E-FF58-4919-A7F3-9567D1C12D07
+ sid-DF216DA8-3E3B-47E0-A7F7-9B1B807D7919
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-248BD3B1-BF44-4994-BF85-B31249B61A3D
+ sid-85723557-4483-4C67-85E3-45CB1A6F83A7
+
+
+
+
+
+
+
+
+
+ sid-BC62037F-6709-4066-A5EE-20913D3F606C
+ sid-248BD3B1-BF44-4994-BF85-B31249B61A3D
+ sid-D87627DB-FB75-4ECE-A7C2-3FBCEE9E5C28
+
+
+
+
+
+
+
+
+
+ sid-85723557-4483-4C67-85E3-45CB1A6F83A7
+ sid-9E490143-B930-487B-8C83-CBAB367C1F81
+ sid-52629B5F-2419-4F9C-B942-5D8AF7275E3C
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-619A8AFA-5799-4B74-B0ED-0AC2A23F44B8
+ sid-BC62037F-6709-4066-A5EE-20913D3F606C
+ sid-0FACBC0E-FF58-4919-A7F3-9567D1C12D07
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-DF216DA8-3E3B-47E0-A7F7-9B1B807D7919
+ sid-52629B5F-2419-4F9C-B942-5D8AF7275E3C
+ sid-664D038B-7B06-4DBC-A47F-2C4CEBD0A874
+
+
+
+
+
+
+
+
+
+
+
+ sid-D87627DB-FB75-4ECE-A7C2-3FBCEE9E5C28
+ sid-8A63D0AD-0EB0-45C6-8471-572BEAA30512
+ sid-F2D5C3CA-7FB2-4CEC-9CBF-C1557F30AC8D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-F2D5C3CA-7FB2-4CEC-9CBF-C1557F30AC8D
+ sid-37EFC97B-FFB5-47B7-A311-9AF7ED10F7A6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-8A63D0AD-0EB0-45C6-8471-572BEAA30512
+ sid-2A06BC7C-BDEC-4484-8BDE-487C28102B31
+
+
+
+
+
+
+
+
+
+
+
+ sid-2A06BC7C-BDEC-4484-8BDE-487C28102B31
+ sid-37EFC97B-FFB5-47B7-A311-9AF7ED10F7A6
+ sid-9E490143-B930-487B-8C83-CBAB367C1F81
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/combinations/nested_and_xor.xml b/examples/combinations/nested_and_xor.xml
new file mode 100644
index 0000000..2da12d4
--- /dev/null
+++ b/examples/combinations/nested_and_xor.xml
@@ -0,0 +1,1173 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-0702479F-0059-432F-8814-1929685AF52B
+
+
+
+
+
+
+
+
+
+
+
+ sid-7B422A57-31B2-4964-AEAB-6B56A877E99E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-F2EFB644-9FEC-4E66-A491-32C39E6602F3
+ sid-AD244BE0-24EA-4D97-9911-10D5AA62FA17
+ sid-4CA3161C-B34E-41AE-B300-17576113D7A9
+
+
+
+
+
+
+
+
+
+
+
+ sid-AD244BE0-24EA-4D97-9911-10D5AA62FA17
+ sid-98389FB7-BFBA-45F9-A497-298019C0A2D0
+ sid-A0A5134E-F917-4AFE-AA76-F886476D30D8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-0702479F-0059-432F-8814-1929685AF52B
+ sid-F2EFB644-9FEC-4E66-A491-32C39E6602F3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-A0A5134E-F917-4AFE-AA76-F886476D30D8
+ sid-CCF1B6DF-9E4C-40A2-A47F-979B835873EF
+ sid-430401F6-6D73-4581-A496-46EA3998DDC1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-98389FB7-BFBA-45F9-A497-298019C0A2D0
+ sid-033A19EA-F8D3-4E08-931F-F6E1FF5B475F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-430401F6-6D73-4581-A496-46EA3998DDC1
+ sid-18E16071-93D1-44AB-A730-0D5EB9A80570
+ sid-FE83A81C-8A83-498D-ACDF-AB115B686081
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-CCF1B6DF-9E4C-40A2-A47F-979B835873EF
+ sid-D4FB55E2-C5E5-48B3-A0B2-E71E5851CA71
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-033A19EA-F8D3-4E08-931F-F6E1FF5B475F
+ sid-4FBC7CFA-B5B4-4A7E-9E0E-3D771032BDCC
+ sid-5B8834C8-DE18-4C3E-9A9E-0C2651CB6EF0
+ sid-7B422A57-31B2-4964-AEAB-6B56A877E99E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-18E16071-93D1-44AB-A730-0D5EB9A80570
+ sid-2C937762-E079-4093-9B7C-0DDF0CFBC678
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-FE83A81C-8A83-498D-ACDF-AB115B686081
+ sid-E2370A59-59DE-4B1F-9B82-9E7FA5A1313D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-2C937762-E079-4093-9B7C-0DDF0CFBC678
+ sid-E2370A59-59DE-4B1F-9B82-9E7FA5A1313D
+ sid-464032E3-02EC-4D5B-AFB9-0DEE7862C069
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-464032E3-02EC-4D5B-AFB9-0DEE7862C069
+ sid-D4FB55E2-C5E5-48B3-A0B2-E71E5851CA71
+ sid-19D5D819-E572-4005-B9A3-6E33F3648230
+
+
+
+
+
+
+
+
+
+
+
+ sid-19D5D819-E572-4005-B9A3-6E33F3648230
+ sid-4FBC7CFA-B5B4-4A7E-9E0E-3D771032BDCC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-4CA3161C-B34E-41AE-B300-17576113D7A9
+ sid-5B8834C8-DE18-4C3E-9A9E-0C2651CB6EF0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/combinations/nested_xor_or.xml b/examples/combinations/nested_xor_or.xml
new file mode 100644
index 0000000..c4853f8
--- /dev/null
+++ b/examples/combinations/nested_xor_or.xml
@@ -0,0 +1,694 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-619A8AFA-5799-4B74-B0ED-0AC2A23F44B8
+
+
+
+
+
+
+
+
+
+
+
+ sid-664D038B-7B06-4DBC-A47F-2C4CEBD0A874
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-0FACBC0E-FF58-4919-A7F3-9567D1C12D07
+ sid-DF216DA8-3E3B-47E0-A7F7-9B1B807D7919
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BC8D2276-041F-4E23-9506-DFB31DE51E61
+ sid-8E788ACA-FBF5-4633-8E2D-4C05EE78F031
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-248BD3B1-BF44-4994-BF85-B31249B61A3D
+ sid-85723557-4483-4C67-85E3-45CB1A6F83A7
+
+
+
+
+
+
+
+
+
+ sid-BC62037F-6709-4066-A5EE-20913D3F606C
+ sid-BC8D2276-041F-4E23-9506-DFB31DE51E61
+ sid-248BD3B1-BF44-4994-BF85-B31249B61A3D
+
+
+
+
+
+
+
+
+
+ sid-85723557-4483-4C67-85E3-45CB1A6F83A7
+ sid-8E788ACA-FBF5-4633-8E2D-4C05EE78F031
+ sid-52629B5F-2419-4F9C-B942-5D8AF7275E3C
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-619A8AFA-5799-4B74-B0ED-0AC2A23F44B8
+ sid-BC62037F-6709-4066-A5EE-20913D3F606C
+ sid-0FACBC0E-FF58-4919-A7F3-9567D1C12D07
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-DF216DA8-3E3B-47E0-A7F7-9B1B807D7919
+ sid-52629B5F-2419-4F9C-B942-5D8AF7275E3C
+ sid-664D038B-7B06-4DBC-A47F-2C4CEBD0A874
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/linear/linear_sequence.xml b/examples/linear/linear_sequence.xml
new file mode 100644
index 0000000..d7280ba
--- /dev/null
+++ b/examples/linear/linear_sequence.xml
@@ -0,0 +1,565 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-901975D0-4ACF-435A-947B-CBE43084E37E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-901975D0-4ACF-435A-947B-CBE43084E37E
+ sid-E99436E0-2FD8-4D15-A06C-ABA769A68FB4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-E99436E0-2FD8-4D15-A06C-ABA769A68FB4
+ sid-1E17AE5F-3352-4DCD-A9D4-28F49EF82206
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-1E17AE5F-3352-4DCD-A9D4-28F49EF82206
+ sid-68983014-C7A8-4FA0-A13C-32ACFD4069CA
+
+
+
+
+
+
+
+
+
+
+
+ sid-68983014-C7A8-4FA0-A13C-32ACFD4069CA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/loops/activity_in_loop.xml b/examples/loops/activity_in_loop.xml
new file mode 100644
index 0000000..321cd39
--- /dev/null
+++ b/examples/loops/activity_in_loop.xml
@@ -0,0 +1,738 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-83719A3B-90E9-4B7C-A856-01CFDFAEA634
+
+
+
+
+
+
+
+
+
+
+
+ sid-9A847C5D-F492-4151-97D2-89F0EDBB7CB8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-83719A3B-90E9-4B7C-A856-01CFDFAEA634
+ sid-5E71CDFE-BFC4-4C8F-90E7-769A6183A854
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5E71CDFE-BFC4-4C8F-90E7-769A6183A854
+ sid-CD07697D-EBBB-4317-BA0E-891DACE2E9D2
+ sid-99738E1C-DD68-435B-9973-72B7D056CEBD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-99738E1C-DD68-435B-9973-72B7D056CEBD
+ sid-7F64E712-80C0-44A6-B020-043C0D01B955
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7F64E712-80C0-44A6-B020-043C0D01B955
+ sid-439F65AC-F859-46DE-B402-1B94595CA4E8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-439F65AC-F859-46DE-B402-1B94595CA4E8
+ sid-9A847C5D-F492-4151-97D2-89F0EDBB7CB8
+ sid-7AF8C813-1851-4336-8B3A-7D4861F72500
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7AF8C813-1851-4336-8B3A-7D4861F72500
+ sid-CD07697D-EBBB-4317-BA0E-891DACE2E9D2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/loops/gateway_in_loop_back.xml b/examples/loops/gateway_in_loop_back.xml
new file mode 100644
index 0000000..0b72055
--- /dev/null
+++ b/examples/loops/gateway_in_loop_back.xml
@@ -0,0 +1,918 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-83719A3B-90E9-4B7C-A856-01CFDFAEA634
+
+
+
+
+
+
+
+
+
+
+
+ sid-9A847C5D-F492-4151-97D2-89F0EDBB7CB8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-83719A3B-90E9-4B7C-A856-01CFDFAEA634
+ sid-5E71CDFE-BFC4-4C8F-90E7-769A6183A854
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5E71CDFE-BFC4-4C8F-90E7-769A6183A854
+ sid-5E30F4D2-4AAC-4026-AFEB-819C16655EEC
+ sid-99738E1C-DD68-435B-9973-72B7D056CEBD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-99738E1C-DD68-435B-9973-72B7D056CEBD
+ sid-7F64E712-80C0-44A6-B020-043C0D01B955
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7F64E712-80C0-44A6-B020-043C0D01B955
+ sid-439F65AC-F859-46DE-B402-1B94595CA4E8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-439F65AC-F859-46DE-B402-1B94595CA4E8
+ sid-9A847C5D-F492-4151-97D2-89F0EDBB7CB8
+ sid-D4F790C4-D37C-49D3-A4DB-2B5B1986AFF9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-D4F790C4-D37C-49D3-A4DB-2B5B1986AFF9
+ sid-8338C8C6-3B83-485C-B47A-7A99ED6D0576
+ sid-006495C0-4021-49E4-9AD8-8414C658ADEC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-006495C0-4021-49E4-9AD8-8414C658ADEC
+ sid-843024BA-2E18-4D30-B6C1-A7317C439DCE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-8338C8C6-3B83-485C-B47A-7A99ED6D0576
+ sid-122EF280-2E04-44C7-AB55-1268BA7292CF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-122EF280-2E04-44C7-AB55-1268BA7292CF
+ sid-843024BA-2E18-4D30-B6C1-A7317C439DCE
+ sid-5E30F4D2-4AAC-4026-AFEB-819C16655EEC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/loops/gateway_in_loop_back_2.xml b/examples/loops/gateway_in_loop_back_2.xml
new file mode 100644
index 0000000..39097da
--- /dev/null
+++ b/examples/loops/gateway_in_loop_back_2.xml
@@ -0,0 +1,1028 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-83719A3B-90E9-4B7C-A856-01CFDFAEA634
+
+
+
+
+
+
+
+
+
+
+
+ sid-9A847C5D-F492-4151-97D2-89F0EDBB7CB8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-83719A3B-90E9-4B7C-A856-01CFDFAEA634
+ sid-5E71CDFE-BFC4-4C8F-90E7-769A6183A854
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5E71CDFE-BFC4-4C8F-90E7-769A6183A854
+ sid-F069A528-692D-4923-90B2-F7933EFCB623
+ sid-99738E1C-DD68-435B-9973-72B7D056CEBD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-99738E1C-DD68-435B-9973-72B7D056CEBD
+ sid-7F64E712-80C0-44A6-B020-043C0D01B955
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7F64E712-80C0-44A6-B020-043C0D01B955
+ sid-439F65AC-F859-46DE-B402-1B94595CA4E8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-439F65AC-F859-46DE-B402-1B94595CA4E8
+ sid-9A847C5D-F492-4151-97D2-89F0EDBB7CB8
+ sid-D4F790C4-D37C-49D3-A4DB-2B5B1986AFF9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-D4F790C4-D37C-49D3-A4DB-2B5B1986AFF9
+ sid-8338C8C6-3B83-485C-B47A-7A99ED6D0576
+ sid-006495C0-4021-49E4-9AD8-8414C658ADEC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-006495C0-4021-49E4-9AD8-8414C658ADEC
+ sid-843024BA-2E18-4D30-B6C1-A7317C439DCE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-8338C8C6-3B83-485C-B47A-7A99ED6D0576
+ sid-122EF280-2E04-44C7-AB55-1268BA7292CF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-122EF280-2E04-44C7-AB55-1268BA7292CF
+ sid-843024BA-2E18-4D30-B6C1-A7317C439DCE
+ sid-5E30F4D2-4AAC-4026-AFEB-819C16655EEC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5E30F4D2-4AAC-4026-AFEB-819C16655EEC
+ sid-F069A528-692D-4923-90B2-F7933EFCB623
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/loops/inner_xor_loop.xml b/examples/loops/inner_xor_loop.xml
new file mode 100644
index 0000000..c7a746b
--- /dev/null
+++ b/examples/loops/inner_xor_loop.xml
@@ -0,0 +1,921 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-944F3A88-E1DA-4F53-849A-2BF603645C31
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-944F3A88-E1DA-4F53-849A-2BF603645C31
+ sid-30C49472-5AE0-4BA2-8B77-0F2BD7918980
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-30C49472-5AE0-4BA2-8B77-0F2BD7918980
+ sid-ABDE7E70-A31D-49D7-998C-79AB49022B66
+ sid-307AF14D-C872-4392-9BEB-469603A44306
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-307AF14D-C872-4392-9BEB-469603A44306
+ sid-E9D95524-DE83-4AB1-8D44-B070362F75BA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-E9D95524-DE83-4AB1-8D44-B070362F75BA
+ sid-32CFDEB4-CA34-4948-A939-0A765A2AEE01
+ sid-4494D22B-FA54-4E19-B232-583FF6B3D907
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-32CFDEB4-CA34-4948-A939-0A765A2AEE01
+ sid-4545AA7B-8AC8-486F-ACDC-B556B4697696
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-4494D22B-FA54-4E19-B232-583FF6B3D907
+ sid-FE95DDDE-0296-4EA3-8E1F-544F561655D5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-4545AA7B-8AC8-486F-ACDC-B556B4697696
+ sid-FE95DDDE-0296-4EA3-8E1F-544F561655D5
+ sid-49F04169-92AC-4FEF-9A0D-CCE622C6826A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-49F04169-92AC-4FEF-9A0D-CCE622C6826A
+ sid-ABDE7E70-A31D-49D7-998C-79AB49022B66
+ sid-9234DEBB-0A8D-40D2-AE75-4B2EAD888F9A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-9234DEBB-0A8D-40D2-AE75-4B2EAD888F9A
+ sid-84F9B3D6-69D9-4CC5-8E14-124ADA9EED01
+
+
+
+
+
+
+
+
+
+
+
+ sid-84F9B3D6-69D9-4CC5-8E14-124ADA9EED01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/loops/loop_with_multiple_xor.xml b/examples/loops/loop_with_multiple_xor.xml
new file mode 100644
index 0000000..4e64485
--- /dev/null
+++ b/examples/loops/loop_with_multiple_xor.xml
@@ -0,0 +1,1106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-033DEC7A-EDA2-4F68-B582-96345CC2AF75
+
+
+
+
+
+
+
+
+
+
+
+ sid-2315521A-BDA3-444E-B453-2D546D9E725B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-4D5E6BA4-4AFE-4B7B-93BC-970382F80678
+ sid-58C0D30F-5D69-47D8-B8B9-BE9132974F2D
+ sid-BB71BB1B-7FF3-454D-80A1-0A47538A0A95
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7211C98C-F9DB-4213-8518-7E80E142769F
+ sid-CAC86FF8-BD07-4CD0-AE15-9E7EBCAD5FC2
+ sid-C66C7BA8-A1EC-4B20-AB05-34C8CB0677E4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-61536FE6-CE69-4696-950D-5F34D021ED0E
+ sid-0059C052-482B-4EB9-A4C3-D7BE77C2A9A2
+ sid-FF2E06FA-9AC0-4AAF-A38A-1A364810BB9B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-DA6DFA7B-B975-4F42-B648-16945322657E
+ sid-05E763BE-555F-4970-A293-8B21FFB34035
+ sid-B8ABDC57-784C-4385-A7A8-0AE0A1F68BD0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BB71BB1B-7FF3-454D-80A1-0A47538A0A95
+ sid-7211C98C-F9DB-4213-8518-7E80E142769F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-58C0D30F-5D69-47D8-B8B9-BE9132974F2D
+ sid-CAC86FF8-BD07-4CD0-AE15-9E7EBCAD5FC2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C66C7BA8-A1EC-4B20-AB05-34C8CB0677E4
+ sid-61536FE6-CE69-4696-950D-5F34D021ED0E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-0059C052-482B-4EB9-A4C3-D7BE77C2A9A2
+ sid-05E763BE-555F-4970-A293-8B21FFB34035
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-FF2E06FA-9AC0-4AAF-A38A-1A364810BB9B
+ sid-DA6DFA7B-B975-4F42-B648-16945322657E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-033DEC7A-EDA2-4F68-B582-96345CC2AF75
+ sid-420662BA-1A5A-4FA0-A090-69EDD35A7906
+ sid-4D5E6BA4-4AFE-4B7B-93BC-970382F80678
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-B8ABDC57-784C-4385-A7A8-0AE0A1F68BD0
+ sid-FF83D8D4-28F9-48DE-928C-436224BB7D4E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-FF83D8D4-28F9-48DE-928C-436224BB7D4E
+ sid-2315521A-BDA3-444E-B453-2D546D9E725B
+ sid-420662BA-1A5A-4FA0-A090-69EDD35A7906
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/loops/nested_loop.xml b/examples/loops/nested_loop.xml
new file mode 100644
index 0000000..63d24cb
--- /dev/null
+++ b/examples/loops/nested_loop.xml
@@ -0,0 +1,810 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-83719A3B-90E9-4B7C-A856-01CFDFAEA634
+
+
+
+
+
+
+
+
+
+
+
+ sid-437B4B97-BFAA-4D51-BF82-E80327DBC169
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-00512A36-599B-405D-8D8E-28DCC240D60B
+ sid-5E71CDFE-BFC4-4C8F-90E7-769A6183A854
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5E71CDFE-BFC4-4C8F-90E7-769A6183A854
+ sid-4C8F7016-0BAB-44CF-A200-D115497CE666
+ sid-99738E1C-DD68-435B-9973-72B7D056CEBD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-99738E1C-DD68-435B-9973-72B7D056CEBD
+ sid-7F64E712-80C0-44A6-B020-043C0D01B955
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7F64E712-80C0-44A6-B020-043C0D01B955
+ sid-439F65AC-F859-46DE-B402-1B94595CA4E8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-439F65AC-F859-46DE-B402-1B94595CA4E8
+ sid-9A847C5D-F492-4151-97D2-89F0EDBB7CB8
+ sid-4C8F7016-0BAB-44CF-A200-D115497CE666
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-9A847C5D-F492-4151-97D2-89F0EDBB7CB8
+ sid-B227C496-2A20-4AAC-A18A-BB076148F2F5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-83719A3B-90E9-4B7C-A856-01CFDFAEA634
+ sid-0916F66C-0712-425F-95ED-A72CC76F7767
+ sid-00512A36-599B-405D-8D8E-28DCC240D60B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-B227C496-2A20-4AAC-A18A-BB076148F2F5
+ sid-437B4B97-BFAA-4D51-BF82-E80327DBC169
+ sid-0916F66C-0712-425F-95ED-A72CC76F7767
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/loops/simple_loop.xml b/examples/loops/simple_loop.xml
new file mode 100644
index 0000000..03c1901
--- /dev/null
+++ b/examples/loops/simple_loop.xml
@@ -0,0 +1,637 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7D7265FF-F159-42CE-889C-74420BD92905
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7D7265FF-F159-42CE-889C-74420BD92905
+ sid-B2748BFE-5F50-47EF-AEDD-0FEB1E738C6F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-B2748BFE-5F50-47EF-AEDD-0FEB1E738C6F
+ sid-412F3F91-FEC6-4F3D-84A6-2082ED8E6BD7
+ sid-8E00F0FE-A774-41CD-8298-A23A274E6277
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-8E00F0FE-A774-41CD-8298-A23A274E6277
+ sid-F135004D-1066-4986-83BA-FAE02DE229EC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-F135004D-1066-4986-83BA-FAE02DE229EC
+ sid-F13B385F-EDEF-4E99-9191-5AED091021F9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-F13B385F-EDEF-4E99-9191-5AED091021F9
+ sid-B9BCE346-2318-4008-B62D-BDF44E447DFF
+ sid-412F3F91-FEC6-4F3D-84A6-2082ED8E6BD7
+
+
+
+
+
+
+
+
+
+
+
+ sid-B9BCE346-2318-4008-B62D-BDF44E447DFF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/loops/two_activities_in_loop.xml b/examples/loops/two_activities_in_loop.xml
new file mode 100644
index 0000000..d93df31
--- /dev/null
+++ b/examples/loops/two_activities_in_loop.xml
@@ -0,0 +1,848 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-83719A3B-90E9-4B7C-A856-01CFDFAEA634
+
+
+
+
+
+
+
+
+
+
+
+ sid-9A847C5D-F492-4151-97D2-89F0EDBB7CB8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-83719A3B-90E9-4B7C-A856-01CFDFAEA634
+ sid-5E71CDFE-BFC4-4C8F-90E7-769A6183A854
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5E71CDFE-BFC4-4C8F-90E7-769A6183A854
+ sid-F68BB0E5-C822-42FF-884E-8CFCD05EA334
+ sid-99738E1C-DD68-435B-9973-72B7D056CEBD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-99738E1C-DD68-435B-9973-72B7D056CEBD
+ sid-7F64E712-80C0-44A6-B020-043C0D01B955
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7F64E712-80C0-44A6-B020-043C0D01B955
+ sid-439F65AC-F859-46DE-B402-1B94595CA4E8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-439F65AC-F859-46DE-B402-1B94595CA4E8
+ sid-9A847C5D-F492-4151-97D2-89F0EDBB7CB8
+ sid-7AF8C813-1851-4336-8B3A-7D4861F72500
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7AF8C813-1851-4336-8B3A-7D4861F72500
+ sid-CD07697D-EBBB-4317-BA0E-891DACE2E9D2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-CD07697D-EBBB-4317-BA0E-891DACE2E9D2
+ sid-F68BB0E5-C822-42FF-884E-8CFCD05EA334
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/loops/two_outgoing_loops.xml b/examples/loops/two_outgoing_loops.xml
new file mode 100644
index 0000000..c10aa4e
--- /dev/null
+++ b/examples/loops/two_outgoing_loops.xml
@@ -0,0 +1,752 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-51D186F5-AAF2-41D5-9CA9-433F8032D4CD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-51D186F5-AAF2-41D5-9CA9-433F8032D4CD
+ sid-493AA70E-867B-4C2F-90AD-92D20DCA6D8E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-493AA70E-867B-4C2F-90AD-92D20DCA6D8E
+ sid-D816F627-ADA4-484E-A55E-39E986644290
+ sid-0DEEADA3-012F-4520-AC5D-F196091EBCDE
+ sid-236E599C-8018-4506-B7A9-1D6109E33114
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-236E599C-8018-4506-B7A9-1D6109E33114
+ sid-05794CAD-0147-4804-96EF-7D85CAC0F66A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-05794CAD-0147-4804-96EF-7D85CAC0F66A
+ sid-9AF5FA6C-47FA-4CB0-B9E5-D27B058B9212
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-9AF5FA6C-47FA-4CB0-B9E5-D27B058B9212
+ sid-9DB529B6-B674-4085-8FFF-DE6062535E92
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-9DB529B6-B674-4085-8FFF-DE6062535E92
+ sid-CF54A624-5C49-4AD6-BAEE-23A9FBAE97F9
+ sid-D816F627-ADA4-484E-A55E-39E986644290
+ sid-0DEEADA3-012F-4520-AC5D-F196091EBCDE
+
+
+
+
+
+
+
+
+
+
+
+ sid-CF54A624-5C49-4AD6-BAEE-23A9FBAE97F9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/main_example/Credit_quote_creation_simplified_SAP Signavio.xml b/examples/main_example/Credit_quote_creation_simplified_SAP Signavio.xml
new file mode 100644
index 0000000..9880505
--- /dev/null
+++ b/examples/main_example/Credit_quote_creation_simplified_SAP Signavio.xml
@@ -0,0 +1,1064 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-38B9A31A-F0F5-4CC6-9215-BEBE7737BC4A
+ sid-DE01AA8F-B36A-4796-9597-651C8B46C6F3
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-DE01AA8F-B36A-4796-9597-651C8B46C6F3
+ sid-25136035-D01E-4DC5-AAF9-FE3F803B865B
+ sid-088B345E-B2CA-455B-A649-B3E8A3C9157E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-25136035-D01E-4DC5-AAF9-FE3F803B865B
+ sid-FA8EA2F2-B2E7-46FC-9B60-441B02FDF8F8
+ sid-2C0CB6FB-7B15-4570-975B-89EBCF4072F4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-2C0CB6FB-7B15-4570-975B-89EBCF4072F4
+ sid-224B5102-FEB8-44B3-9403-387F263E41A5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-04C1509D-573F-4F83-898D-FAD6E7B606DA
+ sid-CA7B85EC-6945-4F46-B7BB-F8208FD568E0
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-CA7B85EC-6945-4F46-B7BB-F8208FD568E0
+ sid-DB57838D-7E05-4F45-B36E-765F6F074084
+ sid-77ADCCB1-8CE0-48B2-BA9C-871C9CBB8214
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-77ADCCB1-8CE0-48B2-BA9C-871C9CBB8214
+ sid-B7ED9CDB-A923-458F-AA47-A5E7812477BE
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-B7ED9CDB-A923-458F-AA47-A5E7812477BE
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-38B9A31A-F0F5-4CC6-9215-BEBE7737BC4A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-FA8EA2F2-B2E7-46FC-9B60-441B02FDF8F8
+ sid-BE5261E4-44C3-4C0E-A6A9-026989C331D1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-088B345E-B2CA-455B-A649-B3E8A3C9157E
+ sid-DB57838D-7E05-4F45-B36E-765F6F074084
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-224B5102-FEB8-44B3-9403-387F263E41A5
+ sid-BE5261E4-44C3-4C0E-A6A9-026989C331D1
+ sid-04C1509D-573F-4F83-898D-FAD6E7B606DA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/misc/multiple_endings.xml b/examples/misc/multiple_endings.xml
new file mode 100644
index 0000000..4608141
--- /dev/null
+++ b/examples/misc/multiple_endings.xml
@@ -0,0 +1,677 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-D8F5EA08-424B-454F-B944-A3AE802AADF5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-D8F5EA08-424B-454F-B944-A3AE802AADF5
+ sid-546D3A7E-C482-4F91-9F9B-70D418F79D6A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-546D3A7E-C482-4F91-9F9B-70D418F79D6A
+ sid-24B83BD2-792C-410B-B5D9-E11DE34A847E
+ sid-D2465F8B-2B1F-4902-8D3E-8C7EDD75FFB7
+ sid-80C7308D-5ADC-47D7-9774-BD839ED62CA1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-24B83BD2-792C-410B-B5D9-E11DE34A847E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-D2465F8B-2B1F-4902-8D3E-8C7EDD75FFB7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-80C7308D-5ADC-47D7-9774-BD839ED62CA1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/misc/multiple_starts.xml b/examples/misc/multiple_starts.xml
new file mode 100644
index 0000000..6d1680f
--- /dev/null
+++ b/examples/misc/multiple_starts.xml
@@ -0,0 +1,512 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-D1C58CBC-89F3-4617-B7EB-0A9174CAA10C
+
+
+
+
+
+
+
+
+
+
+
+ sid-C82B9930-9C9B-4BD2-B7D3-650CCFE91BAA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-D1C58CBC-89F3-4617-B7EB-0A9174CAA10C
+ sid-DC475635-D99F-4A04-9095-7CA88EBE1CF4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C82B9930-9C9B-4BD2-B7D3-650CCFE91BAA
+ sid-750BDEF6-776A-4B65-B4B8-6A9788EE14E2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-DC475635-D99F-4A04-9095-7CA88EBE1CF4
+ sid-750BDEF6-776A-4B65-B4B8-6A9788EE14E2
+ sid-DB8D1E76-E2BD-46B2-B8F9-64DA72898373
+
+
+
+
+
+
+
+
+
+
+
+ sid-DB8D1E76-E2BD-46B2-B8F9-64DA72898373
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/misc/nested_lanes.xml b/examples/misc/nested_lanes.xml
new file mode 100644
index 0000000..7cf9a56
--- /dev/null
+++ b/examples/misc/nested_lanes.xml
@@ -0,0 +1,781 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-966543BB-9C51-496E-86FC-939FF08D42F9
+ sid-CBECC62A-9436-4BFA-8FC5-43C31BD50F8A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-13761D98-14E0-4761-90F3-A0A418CDDA08
+
+
+
+
+
+
+
+
+ sid-38F477AB-DEA5-4D47-A299-0EB75B38FB19
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-03292520-86BC-41EC-AA57-CD9B5073BBF2
+
+
+
+
+
+
+
+
+ sid-B16CE807-A2C6-42A2-A614-29995DE0A331
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-06BC4219-479D-4757-AE4D-430F1E3B3897
+ sid-12244947-E4E9-4AF0-BBCC-E737FE93835F
+
+
+
+
+
+
+
+
+
+
+
+ sid-12244947-E4E9-4AF0-BBCC-E737FE93835F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BCB8EDEF-7F39-473A-9A46-E55BCE8F5834
+ sid-C1F8590E-107F-4355-8AF4-CC59E4D1D79E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-CF8E56B2-20AB-4549-BC7F-031DEDEA2918
+ sid-06BC4219-479D-4757-AE4D-430F1E3B3897
+
+
+
+
+
+
+
+
+
+
+
+ sid-BCB8EDEF-7F39-473A-9A46-E55BCE8F5834
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C1F8590E-107F-4355-8AF4-CC59E4D1D79E
+ sid-CF8E56B2-20AB-4549-BC7F-031DEDEA2918
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/misc/no_start_no_end.xml b/examples/misc/no_start_no_end.xml
new file mode 100644
index 0000000..769e5c9
--- /dev/null
+++ b/examples/misc/no_start_no_end.xml
@@ -0,0 +1,394 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BA09F199-A11C-4850-A48F-27450E7C9C2B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BA09F199-A11C-4850-A48F-27450E7C9C2B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/or_gates/single_or_gateway.xml b/examples/or_gates/single_or_gateway.xml
new file mode 100644
index 0000000..2059ec7
--- /dev/null
+++ b/examples/or_gates/single_or_gateway.xml
@@ -0,0 +1,852 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-651B3646-CE12-4318-AD49-0E4A923044EC
+
+
+
+
+
+
+
+
+
+
+
+ sid-BF4F50B5-1556-4A3C-9D2A-A0A0C347DEB5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-651B3646-CE12-4318-AD49-0E4A923044EC
+ sid-7D9767FF-E6EB-4152-9C65-1B11D6262E68
+
+
+
+
+
+
+
+
+
+ sid-7D9767FF-E6EB-4152-9C65-1B11D6262E68
+ sid-556F8EB4-4CB9-4370-9D83-4BCABC759443
+ sid-5867DA7E-63B0-47C4-845D-ED539FE1A66C
+ sid-DA60A646-4E09-46FC-B8B5-414DE5D41C8F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-556F8EB4-4CB9-4370-9D83-4BCABC759443
+ sid-4E7404D6-ABC8-4A2D-9C3D-3ED593867730
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5867DA7E-63B0-47C4-845D-ED539FE1A66C
+ sid-1E64C13B-6E9F-48FE-AF83-F1BE22730B74
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-DA60A646-4E09-46FC-B8B5-414DE5D41C8F
+ sid-3FF3AA08-B82F-4386-99FF-116B9B157DBA
+
+
+
+
+
+
+
+
+
+ sid-4E7404D6-ABC8-4A2D-9C3D-3ED593867730
+ sid-1E64C13B-6E9F-48FE-AF83-F1BE22730B74
+ sid-3FF3AA08-B82F-4386-99FF-116B9B157DBA
+ sid-A9C805CD-F54B-4827-8B9B-11CDC45CB2C3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-A9C805CD-F54B-4827-8B9B-11CDC45CB2C3
+ sid-BF4F50B5-1556-4A3C-9D2A-A0A0C347DEB5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/xor_gates/3_way_split_xor.xml b/examples/xor_gates/3_way_split_xor.xml
new file mode 100644
index 0000000..90dce09
--- /dev/null
+++ b/examples/xor_gates/3_way_split_xor.xml
@@ -0,0 +1,1264 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7C20EAF0-A42F-4208-9012-2CC4FC1118D7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7C20EAF0-A42F-4208-9012-2CC4FC1118D7
+ sid-5DF81820-6D07-4958-9681-0FEBA039102B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5DF81820-6D07-4958-9681-0FEBA039102B
+ sid-0376B5BD-DB80-4728-9199-6A114C367712
+ sid-B5D0531E-9BDD-4638-944F-61448DA0E7AE
+ sid-32BE7CFB-91FB-4F7D-85D3-913BDC3F6BAD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-0376B5BD-DB80-4728-9199-6A114C367712
+ sid-6C735D09-0A69-462B-94D6-F527C7DF244F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-B5D0531E-9BDD-4638-944F-61448DA0E7AE
+ sid-63E1D956-1376-4FB6-97D2-551794914863
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-32BE7CFB-91FB-4F7D-85D3-913BDC3F6BAD
+ sid-48FBCA3F-2242-4608-A01C-19E92E39A312
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-63E1D956-1376-4FB6-97D2-551794914863
+ sid-3A09E58A-CF69-4E27-84F6-7B9EC0F85054
+ sid-7D190D69-BC82-4AA9-9E14-1FF38C795B2B
+ sid-BCD4E482-8310-42F0-8A72-343DF3E56931
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-48FBCA3F-2242-4608-A01C-19E92E39A312
+ sid-3A09E58A-CF69-4E27-84F6-7B9EC0F85054
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-6C735D09-0A69-462B-94D6-F527C7DF244F
+ sid-CA537795-C404-4AE1-B25A-E6D0A401FBCF
+ sid-F8D6DF55-57BC-4DA7-91B8-FCAC1244D5F0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-CA537795-C404-4AE1-B25A-E6D0A401FBCF
+ sid-F86468A2-F066-4B5C-B094-AEC7EE28F46D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-F8D6DF55-57BC-4DA7-91B8-FCAC1244D5F0
+ sid-80C045A6-0DF3-4EAB-828B-5BD8586F477B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-80C045A6-0DF3-4EAB-828B-5BD8586F477B
+ sid-F86468A2-F066-4B5C-B094-AEC7EE28F46D
+ sid-7D190D69-BC82-4AA9-9E14-1FF38C795B2B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BCD4E482-8310-42F0-8A72-343DF3E56931
+ sid-15CFA5E7-8A65-45C2-8B45-163E451268C6
+
+
+
+
+
+
+
+
+
+
+
+ sid-15CFA5E7-8A65-45C2-8B45-163E451268C6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/xor_gates/double_nested_trailing_values.xml b/examples/xor_gates/double_nested_trailing_values.xml
new file mode 100644
index 0000000..ce521b4
--- /dev/null
+++ b/examples/xor_gates/double_nested_trailing_values.xml
@@ -0,0 +1,1546 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-861F5195-7A99-40DB-BCA7-300E56A25AAE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-861F5195-7A99-40DB-BCA7-300E56A25AAE
+ sid-B2D327FB-A3B2-4F32-82DA-D4EE96E58690
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-B2D327FB-A3B2-4F32-82DA-D4EE96E58690
+ sid-E443563D-51B2-4876-879A-E69D2FA336E0
+ sid-18AECAD2-98FE-4A63-8913-D1E826F5494A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-E443563D-51B2-4876-879A-E69D2FA336E0
+ sid-31FDA2CE-79A6-44F6-8F40-1003F39DDEFF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-18AECAD2-98FE-4A63-8913-D1E826F5494A
+ sid-CD1E2041-B4E6-4513-AAF3-32017B2FCC68
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-31FDA2CE-79A6-44F6-8F40-1003F39DDEFF
+ sid-097FEFF4-272F-40D5-B9EB-FD77A2163F1B
+ sid-86CA6ECD-BE60-411E-B8F2-01F31F1E5F28
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-097FEFF4-272F-40D5-B9EB-FD77A2163F1B
+ sid-97C5B00B-C07B-429D-A2B6-DCCA9DF09032
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-86CA6ECD-BE60-411E-B8F2-01F31F1E5F28
+ sid-FA527604-500B-43BE-8395-D570F6BC2732
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-97C5B00B-C07B-429D-A2B6-DCCA9DF09032
+ sid-FA527604-500B-43BE-8395-D570F6BC2732
+ sid-20FFF92E-5D58-4060-9A02-02005E5978ED
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-20FFF92E-5D58-4060-9A02-02005E5978ED
+ sid-23F5AD48-4CC8-4539-9AAE-BD9469DD5185
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-CD1E2041-B4E6-4513-AAF3-32017B2FCC68
+ sid-2B0D8A8F-090C-49A8-A58C-AD5A74BE1766
+ sid-28E941B4-66F7-4943-8D92-72B0D1BD32C8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-2B0D8A8F-090C-49A8-A58C-AD5A74BE1766
+ sid-FE44AC2D-42FF-42BB-A306-172CF892D914
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-28E941B4-66F7-4943-8D92-72B0D1BD32C8
+ sid-49100AE8-5DFA-4854-AC5B-96C73385FB1D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-FE44AC2D-42FF-42BB-A306-172CF892D914
+ sid-49100AE8-5DFA-4854-AC5B-96C73385FB1D
+ sid-5123D72D-923B-4443-9DDF-40B6B0379E52
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5123D72D-923B-4443-9DDF-40B6B0379E52
+ sid-4283C680-54EC-480B-8CCF-6C6F9BF5B2C3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-23F5AD48-4CC8-4539-9AAE-BD9469DD5185
+ sid-4283C680-54EC-480B-8CCF-6C6F9BF5B2C3
+ sid-D9DDBFC1-CA92-4426-A8D0-36ED6682C5C2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-D9DDBFC1-CA92-4426-A8D0-36ED6682C5C2
+ sid-D7D92E31-7CE8-44BA-95AF-614570F7762F
+
+
+
+
+
+
+
+
+
+
+
+ sid-D7D92E31-7CE8-44BA-95AF-614570F7762F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/xor_gates/longer_xor.xml b/examples/xor_gates/longer_xor.xml
new file mode 100644
index 0000000..a00b710
--- /dev/null
+++ b/examples/xor_gates/longer_xor.xml
@@ -0,0 +1,1178 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-162E80C9-9756-428E-8A66-1E96FB3B1A4D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-162E80C9-9756-428E-8A66-1E96FB3B1A4D
+ sid-364FC0C2-0BFD-416E-BF24-99BDB6CBF638
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-364FC0C2-0BFD-416E-BF24-99BDB6CBF638
+ sid-F40E18BC-C4D5-4401-92F8-15425D102DC6
+ sid-E1BCFB46-13DC-4E2D-BFFC-9A9B24157E09
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-F40E18BC-C4D5-4401-92F8-15425D102DC6
+ sid-88517D91-D43D-474C-9150-6C93093E2940
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-E1BCFB46-13DC-4E2D-BFFC-9A9B24157E09
+ sid-8FF38B7A-227F-4681-8895-0842B7B913BC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-8FF38B7A-227F-4681-8895-0842B7B913BC
+ sid-5B9B48A6-834D-4EFA-9B42-13585AA58625
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5B9B48A6-834D-4EFA-9B42-13585AA58625
+ sid-8B2E8A4B-3D9B-4107-B0CB-D2DBC09ECBC6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-8B2E8A4B-3D9B-4107-B0CB-D2DBC09ECBC6
+ sid-501C5DDC-7D53-49B5-8A47-37162DF5BADD
+ sid-82931C68-5D30-4F83-990D-B5F264449694
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-88517D91-D43D-474C-9150-6C93093E2940
+ sid-E955AB58-AFE6-4E0A-9B51-9FEB6DCD053B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-E955AB58-AFE6-4E0A-9B51-9FEB6DCD053B
+ sid-501C5DDC-7D53-49B5-8A47-37162DF5BADD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-82931C68-5D30-4F83-990D-B5F264449694
+ sid-DCEF2B44-012F-4342-BF16-0681FAEF4EBC
+
+
+
+
+
+
+
+
+
+
+
+ sid-DCEF2B44-012F-4342-BF16-0681FAEF4EBC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/xor_gates/multiple_xor.xml b/examples/xor_gates/multiple_xor.xml
new file mode 100644
index 0000000..0d00496
--- /dev/null
+++ b/examples/xor_gates/multiple_xor.xml
@@ -0,0 +1,924 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-033DEC7A-EDA2-4F68-B582-96345CC2AF75
+
+
+
+
+
+
+
+
+
+
+
+ sid-B8ABDC57-784C-4385-A7A8-0AE0A1F68BD0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-033DEC7A-EDA2-4F68-B582-96345CC2AF75
+ sid-58C0D30F-5D69-47D8-B8B9-BE9132974F2D
+ sid-BB71BB1B-7FF3-454D-80A1-0A47538A0A95
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7211C98C-F9DB-4213-8518-7E80E142769F
+ sid-CAC86FF8-BD07-4CD0-AE15-9E7EBCAD5FC2
+ sid-C66C7BA8-A1EC-4B20-AB05-34C8CB0677E4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-61536FE6-CE69-4696-950D-5F34D021ED0E
+ sid-0059C052-482B-4EB9-A4C3-D7BE77C2A9A2
+ sid-FF2E06FA-9AC0-4AAF-A38A-1A364810BB9B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-DA6DFA7B-B975-4F42-B648-16945322657E
+ sid-05E763BE-555F-4970-A293-8B21FFB34035
+ sid-B8ABDC57-784C-4385-A7A8-0AE0A1F68BD0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BB71BB1B-7FF3-454D-80A1-0A47538A0A95
+ sid-7211C98C-F9DB-4213-8518-7E80E142769F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-58C0D30F-5D69-47D8-B8B9-BE9132974F2D
+ sid-CAC86FF8-BD07-4CD0-AE15-9E7EBCAD5FC2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C66C7BA8-A1EC-4B20-AB05-34C8CB0677E4
+ sid-61536FE6-CE69-4696-950D-5F34D021ED0E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-0059C052-482B-4EB9-A4C3-D7BE77C2A9A2
+ sid-05E763BE-555F-4970-A293-8B21FFB34035
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-FF2E06FA-9AC0-4AAF-A38A-1A364810BB9B
+ sid-DA6DFA7B-B975-4F42-B648-16945322657E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/xor_gates/nested_xor.xml b/examples/xor_gates/nested_xor.xml
new file mode 100644
index 0000000..04b5d70
--- /dev/null
+++ b/examples/xor_gates/nested_xor.xml
@@ -0,0 +1,1109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-6F09E946-4CB8-413C-87CC-790026AC6249
+
+
+
+
+
+
+
+
+
+
+
+ sid-B217324B-CE73-4694-B66B-403D3BD445BB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-6F09E946-4CB8-413C-87CC-790026AC6249
+ sid-5B9013BA-3323-4092-BAE3-2FC179F620E1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-3752DF17-6420-4395-A93C-018D90F88E0A
+ sid-B217324B-CE73-4694-B66B-403D3BD445BB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5B9013BA-3323-4092-BAE3-2FC179F620E1
+ sid-A95C4F77-2BAA-4F47-A3FE-87B5C929F724
+ sid-BCBB683C-3257-432A-9A84-0843A013CB66
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-1BA009A6-3DD5-4BF6-9092-A25232F1E919
+ sid-030B78FB-A37C-496B-AECE-AB7EF865E4F7
+ sid-3752DF17-6420-4395-A93C-018D90F88E0A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BCBB683C-3257-432A-9A84-0843A013CB66
+ sid-ECB58AD4-7D66-418A-9252-AF3AC1918325
+ sid-C2DC3749-93B8-4F30-A70C-BC6562E0E19A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-A95C4F77-2BAA-4F47-A3FE-87B5C929F724
+ sid-8D801F5D-C51D-4719-BCB9-73F748116215
+ sid-F04DCD11-285D-4A8A-A11E-F502AFA57819
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-8D801F5D-C51D-4719-BCB9-73F748116215
+ sid-F16CE26F-0413-41AA-ACF7-BD3755EF7D4B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-F04DCD11-285D-4A8A-A11E-F502AFA57819
+ sid-6D7CF91F-6D6F-4F5E-B3B0-168E47931D73
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-ECB58AD4-7D66-418A-9252-AF3AC1918325
+ sid-C136D286-5C06-4DAF-9E27-147A387BACDA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C2DC3749-93B8-4F30-A70C-BC6562E0E19A
+ sid-3E20BC21-52F6-4940-A266-3BEF70F565CA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C136D286-5C06-4DAF-9E27-147A387BACDA
+ sid-3E20BC21-52F6-4940-A266-3BEF70F565CA
+ sid-1BA009A6-3DD5-4BF6-9092-A25232F1E919
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-6D7CF91F-6D6F-4F5E-B3B0-168E47931D73
+ sid-F16CE26F-0413-41AA-ACF7-BD3755EF7D4B
+ sid-030B78FB-A37C-496B-AECE-AB7EF865E4F7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/xor_gates/nested_xor_with_before_and_after_activities.xml b/examples/xor_gates/nested_xor_with_before_and_after_activities.xml
new file mode 100644
index 0000000..ede28cd
--- /dev/null
+++ b/examples/xor_gates/nested_xor_with_before_and_after_activities.xml
@@ -0,0 +1,1360 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C334E59F-5E84-4741-B701-BF9975AF7EC0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C334E59F-5E84-4741-B701-BF9975AF7EC0
+ sid-3C1936D0-9524-4BB6-B313-9F1FD753756B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-3C1936D0-9524-4BB6-B313-9F1FD753756B
+ sid-74ECBCC7-7F82-460B-B4CB-A5A86F4B5EA5
+ sid-FCA07519-13E8-49C1-8EE7-B2E929D8B2C4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-74ECBCC7-7F82-460B-B4CB-A5A86F4B5EA5
+ sid-8AD19514-E4B9-4AE1-9AD4-C485CF7FC413
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-FCA07519-13E8-49C1-8EE7-B2E929D8B2C4
+ sid-CA69DECD-34E5-4C37-A79A-816C503D00AB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-8AD19514-E4B9-4AE1-9AD4-C485CF7FC413
+ sid-8E6D2767-CEB5-43AD-8630-BB6901AD1895
+ sid-26D2DDEE-3F97-4FE6-87A6-D114EA02605A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-8E6D2767-CEB5-43AD-8630-BB6901AD1895
+ sid-7E3788D8-7B72-4275-8373-40917AD778C3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-26D2DDEE-3F97-4FE6-87A6-D114EA02605A
+ sid-A70C9071-7CC3-483B-8582-CB884E5EC685
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7E3788D8-7B72-4275-8373-40917AD778C3
+ sid-A14ED911-15B9-4D87-B3CA-87E63DBB40A6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-A70C9071-7CC3-483B-8582-CB884E5EC685
+ sid-8144C6A0-870F-4AB5-B548-200B9AAAF230
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-A14ED911-15B9-4D87-B3CA-87E63DBB40A6
+ sid-8144C6A0-870F-4AB5-B548-200B9AAAF230
+ sid-3C7735CF-2742-4DDE-B6BF-2271EEEFA98C
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-CA69DECD-34E5-4C37-A79A-816C503D00AB
+ sid-E3D36174-A21D-4FD6-9F86-0D32CC8E3BD4
+ sid-891F07A6-CB58-4E1E-91EE-BABFDF63A6E5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-891F07A6-CB58-4E1E-91EE-BABFDF63A6E5
+ sid-2C3458A6-EABA-4FCE-92B2-84BC47AD557C
+
+
+
+
+
+
+
+
+
+
+
+ sid-2C3458A6-EABA-4FCE-92B2-84BC47AD557C
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-3C7735CF-2742-4DDE-B6BF-2271EEEFA98C
+ sid-E3D36174-A21D-4FD6-9F86-0D32CC8E3BD4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/xor_gates/nested_xor_with_double_ending.xml b/examples/xor_gates/nested_xor_with_double_ending.xml
new file mode 100644
index 0000000..3e3d2e0
--- /dev/null
+++ b/examples/xor_gates/nested_xor_with_double_ending.xml
@@ -0,0 +1,1234 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-3FD1BA97-590F-4D1A-8598-181647AE708E
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-3FD1BA97-590F-4D1A-8598-181647AE708E
+ sid-3467BBAF-9ECE-4E17-AD34-9C955E48A84C
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-3467BBAF-9ECE-4E17-AD34-9C955E48A84C
+ sid-5339D30F-AD39-4C92-BBFD-FD7B11D9F93C
+ sid-A56206C8-5878-428B-A336-082FC6DA9405
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5339D30F-AD39-4C92-BBFD-FD7B11D9F93C
+ sid-F1A4FA9C-C68B-43E0-B270-214D4BD0ADA4
+
+
+
+
+
+
+
+
+
+
+
+ sid-A56206C8-5878-428B-A336-082FC6DA9405
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-F1A4FA9C-C68B-43E0-B270-214D4BD0ADA4
+ sid-1B272420-F6B2-40E8-A427-3D483A7C0079
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-1B272420-F6B2-40E8-A427-3D483A7C0079
+ sid-F7F42746-99CD-4DF8-8BD5-834A251D027C
+ sid-D1115244-4F74-4752-9CE9-244E782B97AA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-F7F42746-99CD-4DF8-8BD5-834A251D027C
+ sid-AF9BCC0A-3A0F-4DF9-8756-B4AFEE60725F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-D1115244-4F74-4752-9CE9-244E782B97AA
+ sid-5D7D25EB-9C03-4A9D-823A-308F240EF759
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-AF9BCC0A-3A0F-4DF9-8756-B4AFEE60725F
+ sid-3290F556-D993-46F0-8AE4-1638C2165C94
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-5D7D25EB-9C03-4A9D-823A-308F240EF759
+ sid-08C99D01-72A2-4E8D-A403-141BCF9115ED
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-3290F556-D993-46F0-8AE4-1638C2165C94
+ sid-08C99D01-72A2-4E8D-A403-141BCF9115ED
+ sid-E0284A3F-70CA-44FC-94E4-76C5A86F2EE7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-E0284A3F-70CA-44FC-94E4-76C5A86F2EE7
+ sid-F4024213-8905-4C42-BD7C-E1F9445DBFF0
+
+
+
+
+
+
+
+
+
+
+
+ sid-F4024213-8905-4C42-BD7C-E1F9445DBFF0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/xor_gates/single_xor.xml b/examples/xor_gates/single_xor.xml
new file mode 100644
index 0000000..f21bc2c
--- /dev/null
+++ b/examples/xor_gates/single_xor.xml
@@ -0,0 +1,740 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BB798069-B31E-4A5F-A1E5-27BF68840909
+
+
+
+
+
+
+
+
+
+
+
+ sid-2FBA0CCE-59BE-47CA-8EA1-5066CAAC339D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-E257E9EB-3968-45CA-A3DB-C1B57BC6E6E0
+ sid-58C0D30F-5D69-47D8-B8B9-BE9132974F2D
+ sid-BB71BB1B-7FF3-454D-80A1-0A47538A0A95
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-7211C98C-F9DB-4213-8518-7E80E142769F
+ sid-CAC86FF8-BD07-4CD0-AE15-9E7EBCAD5FC2
+ sid-C66C7BA8-A1EC-4B20-AB05-34C8CB0677E4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BB71BB1B-7FF3-454D-80A1-0A47538A0A95
+ sid-7211C98C-F9DB-4213-8518-7E80E142769F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-58C0D30F-5D69-47D8-B8B9-BE9132974F2D
+ sid-CAC86FF8-BD07-4CD0-AE15-9E7EBCAD5FC2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-C66C7BA8-A1EC-4B20-AB05-34C8CB0677E4
+ sid-2FBA0CCE-59BE-47CA-8EA1-5066CAAC339D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sid-BB798069-B31E-4A5F-A1E5-27BF68840909
+ sid-E257E9EB-3968-45CA-A3DB-C1B57BC6E6E0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/explainer/README.md b/explainer/README.md
new file mode 100644
index 0000000..5e9cc52
--- /dev/null
+++ b/explainer/README.md
@@ -0,0 +1,15 @@
+# Symbolic Explanations of Process Conformance Violations
+This module is made by Marcus Rost, for his thesis subject, **Symbolic Explanations for Control-Flow Objects**.
+
+The code should work properly, with some hard-coded parts that requires the data set for the signal code to function. This module is more seen as a proof of concept, where some core functions from explainability theory is utilized.
+
+## Overview
+The module mainly consists of 2 classes, ExplainerRegex and ExplainerSignal.
+
+**ExplainerRegex** is meant to simulate a real event log and system, with traces and constraints, using regex patterns.
+
+**ExplainerSignal** uses real event logs to calculate the explanations. This uses SAP Signavio's API to do so, but should in reality have it's own interpreter for the Signal queries, instead of having to make API calls.
+
+Currently, the Signal code is sort of bad and specialized for the specific data set used. Hopefully, someone can see the value of what it done, and generalize it further.
+
+There is also 2 Notebook's located in `explainer/tutorial`, but I recommend doing `bpmn2constraints/tutorial/tutorial.ipynb` first, to see how to do the configuration for the API works.
diff --git a/explainer/__init__.py b/explainer/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/explainer/explainer_regex.py b/explainer/explainer_regex.py
new file mode 100644
index 0000000..33653c8
--- /dev/null
+++ b/explainer/explainer_regex.py
@@ -0,0 +1,475 @@
+import math
+import re
+from itertools import product
+from explainer.explainer_util import *
+
+
+class ExplainerRegex:
+ def __init__(self):
+ self.constraints = [] # List to store constraints (constraint patterns)
+ self.adherent_trace = None
+ self.adherent_traces = []
+ self.minimal_solution = False
+
+ def set_minimal_solution(self, minimal_solution):
+ """
+ Tells the explainer to generate minimal solutions
+ Note: This will increase computations significantly
+
+ Args:
+ minimal_solution (bool): True to generate minimal solutions, False if it should be the first possible
+ """
+ self.minimal_solution = minimal_solution
+
+ def add_constraint(self, regex):
+ """
+ Adds a new constraint and updates the nodes list.
+
+ :param regex: A regular expression representing the constraint.
+ """
+ self.constraints.append(regex)
+ max_length = 0
+ for con in self.constraints:
+ max_length += len(con)
+ if self.contradiction(len(regex) + max_length):
+ self.constraints.remove(regex)
+ print(f"Constraint {regex} contradicts the other constraints.")
+
+ def remove_constraint(self, idx):
+ """
+ Removes a constraint by index and updates the nodes list if necessary.
+
+ :param idx: Index of the constraint to be removed.
+ """
+ if 0 <= idx < len(self.constraints):
+ removed_regex = self.constraints.pop(idx)
+ removed_nodes = set(filter(str.isalpha, removed_regex))
+
+ # Re-evaluate nodes to keep based on remaining constraints
+ remaining_nodes = set(filter(str.isalpha, "".join(self.constraints)))
+ self.nodes = remaining_nodes
+
+ # Optionally, remove nodes that are no longer in any constraint
+ for node in removed_nodes:
+ if node not in remaining_nodes:
+ self.nodes.discard(node)
+
+ def activation(self, trace, constraints=None):
+ """
+ Checks if any of the nodes in the trace activates any constraint.
+
+ :param trace: A Trace instance.
+ :return: Boolean indicating if any constraint is activated.
+ """
+ if not constraints:
+ constraints = self.constraints
+ con_activation = [0] * len(constraints)
+ activated = False
+ for idx, con in enumerate(constraints):
+ if activated:
+ activated = False
+ continue
+ target = self.identify_existance_constraints(con)
+ if target:
+ con_activation[idx] = 1
+ continue
+ for event in trace:
+ if event in con:
+ con_activation[idx] = 1
+ activated = True
+ break
+ return con_activation
+
+ def identify_existance_constraints(self, pattern):
+ """
+ Identifies existance constraints within a pattern.
+
+ :param pattern: The constraint pattern as a string.
+ :return: A tuple indicating the type of existance constraint and the node involved.
+ """
+ # Check for AtLeastOne constraint
+ for match in re.finditer(r"(? 100:
+ return f"{explanation}\n Maximum depth of {depth -1} reached"
+ score = self.evaluate_similarity(working_trace)
+ return self.operate_on_trace(working_trace, score, explanation, depth)
+
+ def operate_on_trace(self, trace, score, explanation_path, depth=0):
+ """
+ Finds and applies modifications to the trace to make it conformant.
+
+ :param trace: The trace to be modified.
+ :param score: The similarity score of the trace.
+ :param explanation_path: The current explanation path.
+ :param depth: The current recursion depth.
+ :return: A string explaining why the best subtrace is non-conformant or a message indicating the maximum depth has been reached.
+ """
+ explanation = None
+ counter_factuals = self.modify_subtrace(trace)
+ best_subtrace = None
+ best_score = -float("inf")
+ for subtrace in counter_factuals:
+ current_score = self.evaluate_similarity(subtrace[0])
+ if current_score > best_score and current_score > score:
+ best_score = current_score
+ best_subtrace = subtrace[0]
+ explanation = subtrace[1]
+ if best_subtrace == None:
+ for subtrace in counter_factuals:
+ self.operate_on_trace(subtrace[0], score, explanation_path, depth + 1)
+ explanation_string = explanation_path + "\n" + str(explanation)
+ return self.counter_factual_helper(best_subtrace, explanation_string, depth + 1)
+
+ def get_nodes_from_constraint(self, constraint=None):
+ """
+ Extracts unique nodes from a constraint pattern.
+
+ :param constraint: The constraint pattern as a string.
+ :return: A list of unique nodes found within the constraint.
+ """
+ if constraint is None:
+ all_nodes = set()
+ for con in self.constraints:
+ all_nodes.update(re.findall(r"[A-Za-z]", con))
+ return list(set(all_nodes))
+ else:
+ return list(set(re.findall(r"[A-Za-z]", constraint)))
+
+ def modify_subtrace(self, trace):
+ """
+ Modifies the given trace to meet constraints by adding nodes where the pattern fails.
+
+ Parameters:
+ - trace: A list of node identifiers
+
+ Returns:
+ - A list of potential subtraces each modified to meet constraints.
+ """
+ potential_subtraces = []
+ possible_additions = self.get_nodes_from_constraint()
+ for i, s_trace in enumerate(get_iterative_subtrace(trace)):
+ for con in self.constraints:
+ new_trace_str = "".join(s_trace)
+ match = re.search(con, new_trace_str)
+ if not match:
+ for add in possible_additions:
+ potential_subtraces.append(
+ [
+ Trace(s_trace + [add] + trace.nodes[i + 1 :]),
+ f"Addition (Added {add} at position {i+1}): "
+ + "->".join(s_trace + [add] + trace.nodes[i + 1 :]),
+ ]
+ )
+ potential_subtraces.append(
+ [
+ Trace(s_trace[:-1] + [add] + trace.nodes[i:]),
+ f"Addition (Added {add} at position {i}): "
+ + "->".join(s_trace[:-1] + [add] + trace.nodes[i:]),
+ ]
+ )
+
+ potential_subtraces.append(
+ [
+ Trace(s_trace[:-1] + trace.nodes[i + 1 :]),
+ f"Subtraction (Removed {s_trace[i]} from position {i}): "
+ + "->".join(s_trace[:-1] + trace.nodes[i + 1 :]),
+ ]
+ )
+ return potential_subtraces
+
+ def evaluate_similarity(self, trace):
+ """
+ Calculates the similarity between the adherent trace and the given trace using the Levenshtein distance.
+
+ :param trace: The trace to compare with the adherent trace.
+ :return: A normalized score indicating the similarity between the adherent trace and the given trace.
+ """
+ trace_len = len("".join(trace))
+ length = len(self.adherent_trace)
+ lev_distance = levenshtein_distance(self.adherent_trace, "".join(trace))
+ max_distance = max(length, trace_len)
+ normalized_score = 1 - lev_distance / max_distance
+ return normalized_score
+
+ def determine_conformance_rate(self, event_log, constraints=None):
+ """
+ Determines the conformance rate of the event log based on the given constraints.
+
+ :param event_log: The event log to analyze.
+ :param constraints: The constraints to check against the event log.
+ :return: The conformance rate as a float between 0 and 1, or a message if no constraints are provided.
+ """
+ if not self.constraints and not constraints:
+ return "The explainer have no constraints"
+ len_log = len(event_log)
+ if len_log == 0:
+ return 1
+ non_conformant = 0
+ if constraints == None:
+ constraints = self.constraints
+ for trace, count in event_log.log.items():
+ for con in constraints:
+ if not re.search(con, "".join(trace)):
+ non_conformant += count
+ break
+ return (len_log - non_conformant) / len_log
+
+ def determine_fitness_rate(self, event_log, constraints=None):
+ """
+ Determines the fitness rate of the event log based on given constraints.
+
+ :param event_log: The event log to analyze.
+ :param constraints: The constraints to check against the event log. If None, use self.constraints.
+ :return: The fitness rate as a float between 0 and 1.
+ """
+ if not self.constraints and not constraints:
+ return "The explainer have no constraints"
+ if constraints == None:
+ constraints = self.constraints
+ conformant = 0
+ for con in constraints:
+ for trace, count in event_log.log.items():
+ if re.search(con, "".join(trace)):
+ conformant += count
+ return conformant / (len(event_log) * len(constraints))
+
+ def variant_ctrb_to_fitness(self, event_log, trace, constraints=None):
+ """
+ Determines the contribution of a specific trace variant to the fitness loss of the event log.
+
+ :param event_log: The event log to analyze.
+ :param trace: The trace variant to calculate its contribution.
+ :param constraints: The constraints to check against the event log. If None, use self.constraints.
+ :return: The contribution of the trace variant to the fitness as a float.
+ """
+ if not self.constraints and not constraints:
+ return "The explainer have no constraints"
+ if not constraints:
+ constraints = self.constraints
+ total_traces = len(event_log)
+ contribution_of_trace = 0
+ for con in constraints:
+ if not re.search(con, "".join(trace)):
+ contribution_of_trace += 1
+ nr = event_log.get_variant_count(trace)
+ contribution_of_trace = contribution_of_trace / len(constraints)
+ contribution_of_trace = nr * contribution_of_trace
+ return contribution_of_trace / total_traces
+
+ def variant_ctrb_to_conformance_loss(self, event_log, trace, constraints=None):
+ """
+ Calculates the contribution of a specific trace to the conformance loss of the event log.
+
+ :param event_log: The event log to analyze.
+ :param trace: The trace to calculate its contribution.
+ :param constraints: The constraints to check against the event log.
+ :return: The contribution of the trace to the conformance loss as a float between 0 and 1.
+ """
+ if not self.constraints and not constraints:
+ return "The explainer have no constraints"
+ if not constraints:
+ constraints = self.constraints
+ total_traces = len(event_log)
+ contribution_of_trace = 0
+
+ if not self.conformant(trace, constraints=constraints):
+ contribution_of_trace = event_log.get_variant_count(trace)
+ return contribution_of_trace / total_traces
+
+ def constraint_ctrb_to_conformance(self, log, constraints, index):
+ """Determines the Shapley value-based contribution of a constraint to a the
+ overall conformance rate.
+ Args:
+ log (dictionary): The event log, where keys are strings and values are
+ ints
+ constraints (list): A list of constraints (regexp strings)
+ index (int): The
+ Returns:
+ float: The contribution of the constraint to the overall conformance
+ rate
+ """
+ if len(constraints) < index:
+ raise Exception("Constraint not in constraint list.")
+ contributor = constraints[index]
+ sub_ctrbs = []
+ reduced_constraints = [c for c in constraints if not c == contributor]
+ subsets = determine_powerset(reduced_constraints)
+ for subset in subsets:
+ lsubset = list(subset)
+ constraints_without = [c for c in constraints if c in lsubset]
+ constraints_with = [c for c in constraints if c in lsubset + [contributor]]
+ weight = (
+ math.factorial(len(lsubset))
+ * math.factorial(len(constraints) - 1 - len(lsubset))
+ ) / math.factorial(len(constraints))
+ sub_ctrb = weight * (
+ self.determine_conformance_rate(log, constraints_without)
+ - self.determine_conformance_rate(log, constraints_with)
+ )
+ sub_ctrbs.append(sub_ctrb)
+ return sum(sub_ctrbs)
+
+ def constraint_ctrb_to_fitness(self, log, constraints, index):
+ """
+ Determines the Shapley value-based contribution of a constraint to the overall fitness rate.
+
+ :param log: The event log, where keys are strings and values are counts of trace variants.
+ :param constraints: A list of constraints (regexp strings).
+ :param index: The index of the constraint in the constraints list.
+ :return: The contribution of the constraint to the overall conformance rate as a float.
+ """
+ if len(constraints) < index:
+ raise Exception("Constraint not in constraint list.")
+ if not self.constraints and not constraints:
+ return "The explainer have no constraints"
+ if not constraints:
+ constraints = self.constraints
+ contributor = constraints[index]
+ ctrb_count = 0
+ for trace, count in log.log.items():
+ if not re.search(contributor, "".join(trace)):
+ ctrb_count += count
+ return ctrb_count / (len(log) * len(constraints))
diff --git a/explainer/explainer_signal.py b/explainer/explainer_signal.py
new file mode 100644
index 0000000..48e77a2
--- /dev/null
+++ b/explainer/explainer_signal.py
@@ -0,0 +1,552 @@
+from explainer.explainer_util import *
+import re
+import math
+from tutorial.SignavioAuthenticator import SignavioAuthenticator
+import requests
+from tutorial.conf import *
+
+
+class ExplainerSignal:
+ def __init__(self):
+ self.constraints = [] # List to store constraints (constraint patterns)
+ self.adherent_trace = None
+ self.adherent_traces = []
+ self.minimal_solution = False
+ self.authenticator = SignavioAuthenticator(
+ system_instance, workspace_id, user_name, pw
+ )
+ self.auth_data = self.authenticator.authenticate()
+ self.cookies = {
+ "JSESSIONID": self.auth_data["jsesssion_ID"],
+ "LBROUTEID": self.auth_data["lb_route_ID"],
+ }
+ self.headers = {
+ "Accept": "application/json",
+ "x-signavio-id": self.auth_data["auth_token"],
+ }
+ self.event_log = EventLog()
+ self.signal_endpoint = None
+ self.cache = {}
+
+ def set_endpoint(self, endpoint="/g/api/pi-graphql/signal"):
+ """
+ Configures the end point of the SIGNAL API
+
+ Args:
+ endpoint (str, optional): The end point address.
+ Defaults to "/g/api/pi-graphql/signal".
+ """
+ self.signal_endpoint = system_instance + endpoint
+ self.load_variants()
+
+ def remove_constraint(self, idx):
+ """
+ Removes a constraint by index and updates the nodes list if necessary.
+
+ :param idx: Index of the constraint to be removed.
+ """
+ if idx < len(self.constraints):
+ del self.constraints[idx]
+
+ def activation(self, trace, constraints=None):
+ """
+ Checks if any of the nodes in the trace activates any constraint.
+
+ :param trace: A Trace instance.
+ :return: Boolean indicating if any constraint is activated.
+ """
+ if constraints is None:
+ constraints = self.constraints
+
+ for node in trace:
+ for constraint in constraints:
+ if re.search(constraint, node):
+ return True
+ return False
+
+ def add_constraint(self, constr):
+ """
+ Adds a new constraint and updates the nodes list.
+
+ :param constr: A regular expression or Signal constrain representing the constraint.
+ """
+ self.constraints.append(constr)
+
+ def conformant(self, trace, constraints=None):
+ """
+ Checks if the trace is conformant according to all the constraints.
+
+ :param trace: A Trace instance.
+ :return: Boolean indicating if the trace is conformant with all constraints.
+ """
+ if constraints == None:
+ return self.post_query_trace_in_dataset(trace, self.constraints)
+ return self.post_query_trace_in_dataset(trace, constraints)
+
+ def minimal_expl(self, trace):
+ """
+ Provides a minimal explanation for non-conformance, given the trace and constraints.
+
+ :param trace: A Trace instance.
+ :return: Explanation of why the trace is non-conformant.
+ """
+ if self.conformant(trace):
+ return "The trace is already conformant, no changes needed."
+ explanations = None
+
+ for constraint in self.constraints:
+ for subtrace in get_sublists(trace):
+ trace_str = "".join(subtrace)
+ if not re.search(constraint, trace_str):
+ explanations = (
+ f"Constraint ({constraint}) is violated by subtrace: {subtrace}"
+ )
+ break
+
+ if explanations:
+ return "Non-conformance due to: " + explanations
+ else:
+ return "Trace is non-conformant, but the specific constraint violation could not be determined."
+
+ def counterfactual_expl(self, trace):
+ """
+ Generates a counterfactual explanation for a given trace.
+
+ :param trace: The trace to be explained.
+ :return: A string explaining why the trace is non-conformant or a message indicating no changes are needed.
+ """
+ result = self.get_all_conformant_traces()
+ best_score = -float("inf")
+ for res in result:
+ current_score = self.evaluate_similarity(trace, "".join(res[0]))
+ if current_score > best_score:
+ best_score = current_score
+ self.adherent_trace = Trace(res[0])
+
+ return self.operate_on_trace(trace, 0, "")
+
+ def counter_factual_helper(self, working_trace, explanation, depth=0):
+ """
+ Recursively explores counterfactual explanations for a working trace.
+
+ :param working_trace: The trace being explored.
+ :param explanation: The current explanation path.
+ :param depth: The current recursion depth.
+ :return: A string explaining why the working trace is non-conformant or a message indicating the maximum depth has been reached.
+ """
+ if self.conformant(working_trace):
+ return f"{explanation}"
+ if depth > 100:
+ return f"{explanation}\n Maximum depth of {depth -1} reached"
+ return self.operate_on_trace(working_trace, 0, explanation, depth)
+
+ def operate_on_trace(self, trace, score, explanation_path, depth=0):
+ """
+ Finds and applies modifications to the trace to make it conformant.
+
+ :param trace: The trace to be modified.
+ :param score: The similarity score of the trace.
+ :param explanation_path: The current explanation path.
+ :param depth: The current recursion depth.
+ :return: A string explaining why the best subtrace is non-conformant or a message indicating the maximum depth has been reached.
+ """
+ explanation = None
+ counter_factuals = self.modify_subtrace(trace)
+ best_subtrace = None
+ best_score = -float("inf")
+ for subtrace in counter_factuals:
+ current_score = self.evaluate_similarity(subtrace[0])
+ if current_score > best_score:
+ best_score = current_score
+ best_subtrace = subtrace[0]
+ explanation = subtrace[1]
+ if best_subtrace == None:
+ for subtrace in counter_factuals:
+ self.operate_on_trace(subtrace[0], score, explanation_path, depth + 1)
+ explanation_string = explanation_path + "\n" + str(explanation)
+ return self.counter_factual_helper(best_subtrace, explanation_string, depth + 1)
+
+ def modify_subtrace(self, trace):
+ """
+ Modifies the given trace to meet constraints by adding nodes where the pattern fails.
+
+ Parameters:
+ - trace: A list of node identifiers
+
+ Returns:
+ - A list of potential subtraces each modified to meet constraints.
+ """
+ potential_subtraces = []
+ possible_additions = self.get_nodes_from_constraint()
+ for i, s_trace in enumerate(get_iterative_subtrace(trace)):
+ for con in self.constraints:
+ new_trace_str = "".join(s_trace)
+ match = re.search(con, new_trace_str)
+ if not match:
+ for add in possible_additions:
+ potential_subtraces.append(
+ [
+ Trace(s_trace + [add] + trace.nodes[i + 1 :]),
+ f"Addition (Added {add} at position {i+1}): "
+ + "->".join(s_trace + [add] + trace.nodes[i + 1 :]),
+ ]
+ )
+ potential_subtraces.append(
+ [
+ Trace(s_trace[:-1] + [add] + trace.nodes[i:]),
+ f"Addition (Added {add} at position {i}): "
+ + "->".join(s_trace[:-1] + [add] + trace.nodes[i:]),
+ ]
+ )
+
+ potential_subtraces.append(
+ [
+ Trace(s_trace[:-1] + trace.nodes[i + 1 :]),
+ f"Subtraction (Removed {s_trace[i]} from position {i}): "
+ + "->".join(s_trace[:-1] + trace.nodes[i + 1 :]),
+ ]
+ )
+ return potential_subtraces
+
+ def get_nodes_from_constraint(self, constraint=None):
+ """
+ Extracts unique nodes from a constraint pattern.
+
+ :param constraint: The constraint pattern as a string.
+ :return: A list of unique nodes found within the constraint.
+ """
+ if constraint is None:
+ all_nodes = set()
+ for con in self.constraints:
+ all_nodes.update(self.filter_keywords(con))
+ return list(set(all_nodes))
+ else:
+ return list(set(self.filter_keywords(constraint)))
+
+ def filter_keywords(self, text):
+ """
+ Extracts the events from a SIGNAL constraint
+
+ Args:
+ text (String): The SIGNAL constraint
+
+ Returns:
+ [String]: A list of the filtered events from the SIGNAL constraint
+ """
+ text = re.sub(r"\s+", "_", text.strip())
+ words = re.findall(r"\b[A-Z_a-z]+\b", text)
+ modified_words = [word.replace("_", " ") for word in words]
+ filtered_words = [
+ word for word in modified_words if word.strip() not in SIGNAL_KEYWORDS
+ ]
+
+ return filtered_words
+
+ def evaluate_similarity(self, trace, cmp_trace=None):
+ """
+ Calculates the similarity between the adherent trace and the given trace using the Levenshtein distance.
+
+ :param trace: The trace to compare with the adherent trace.
+ :return: A normalized score indicating the similarity between the adherent trace and the given trace.
+ """
+ if cmp_trace == None:
+ cmp_trace = "".join(self.adherent_trace)
+ trace_len = len("".join(trace))
+ length = len(cmp_trace)
+ lev_distance = levenshtein_distance(cmp_trace, "".join(trace))
+ max_distance = max(length, trace_len)
+ normalized_score = 1 - lev_distance / max_distance
+ return normalized_score
+
+ def determine_conformance_rate(self, event_log=None, constraints=None):
+ """
+ Determines the conformance rate of the event log based on the given constraints.
+
+ :param event_log: The event log to analyze.
+ :param constraints: The constraints to check against the event log.
+ :return: The conformance rate as a float between 0 and 1, or a message if no constraints are provided.
+ """
+ if constraints == None:
+ constraints = self.constraints
+ if constraints == []:
+ return 1
+ non_conformant = 0
+ non_conformant = self.check_violations(constraints)
+
+ len_log = self.get_total_cases()
+
+ return (len_log - non_conformant) / len_log
+
+ def determine_fitness_rate(self, event_log=None, constraints=None):
+ """
+ Determines the fitness rate of the event log based on given constraints.
+
+ :param event_log: The event log to analyze.
+ :param constraints: The constraints to check against the event log. If None, use self.constraints.
+ :return: The fitness rate as a float between 0 and 1.
+ """
+ if not constraints:
+ constraints = self.constraints
+ len_log = self.get_total_cases()
+ total_conformance = 0
+ for con in constraints:
+ total_conformance += self.check_conformance(con)
+ return total_conformance / (len_log * len(constraints))
+
+ def variant_ctrb_to_conformance_loss(self, event_log, trace, constraints=None):
+ """
+ Calculates the contribution of a specific trace to the conformance loss of the event log.
+
+ :param event_log: The event log to analyze.
+ :param trace: The trace to calculate its contribution.
+ :param constraints: The constraints to check against the event log.
+ :return: The contribution of the trace to the conformance loss as a float between 0 and 1.
+ """
+ if not self.constraints and not constraints:
+ return "The explainer have no constraints"
+ if not constraints:
+ constraints = self.constraints
+ total_traces = len(event_log)
+ contribution_of_trace = 0
+ if not self.conformant(trace, constraints=constraints):
+ contribution_of_trace = event_log.get_variant_count(trace)
+
+ return contribution_of_trace / total_traces
+
+ def variant_ctrb_to_fitness(self, event_log, trace, constraints=None):
+ """
+ Determines the contribution of a specific trace variant to the fitness of the event log.
+
+ :param event_log: The event log to analyze.
+ :param trace: The trace variant to calculate its contribution.
+ :param constraints: The constraints to check against the event log. If None, use self.constraints.
+ :return: The contribution of the trace variant to the fitness as a float.
+ """
+ if not self.constraints and not constraints:
+ return "The explainer have no constraints"
+ if not constraints:
+ constraints = self.constraints
+ total_traces = len(event_log)
+ contribution_of_trace = 0
+ for con in constraints:
+ if not self.conformant(trace, constraints=[con]):
+ contribution_of_trace += 1
+ nr = event_log.get_variant_count(trace)
+ contribution_of_trace = contribution_of_trace / len(constraints)
+ contribution_of_trace = nr * contribution_of_trace
+ return contribution_of_trace / total_traces
+
+ def constraint_ctrb_to_conformance(self, log=None, constraints=None, index=-1):
+ """Determines the Shapley value-based contribution of a constraint to a the
+ overall conformance rate.
+ Args:
+ log (dictionary): The event log, where keys are strings and values are
+ ints
+ constraints (list): A list of constraints (regexp strings)
+ index (int): The
+ Returns:
+ float: The contribution of the constraint to the overall conformance
+ rate
+ """
+ if not constraints:
+ constraints = self.constraints
+ if len(constraints) < index:
+ raise Exception("Constraint not in constraint list.")
+ if index == -1:
+ return f"Add an index for the constraint:\n {constraints}"
+ contributor = constraints[index]
+ sub_ctrbs = []
+ reduced_constraints = [c for c in constraints if not c == contributor]
+ subsets = determine_powerset(reduced_constraints)
+ for subset in subsets:
+ lsubset = list(subset)
+ constraints_without = [c for c in constraints if c in lsubset]
+ constraints_with = [c for c in constraints if c in lsubset + [contributor]]
+ weight = (
+ math.factorial(len(lsubset))
+ * math.factorial(len(constraints) - 1 - len(lsubset))
+ ) / math.factorial(len(constraints))
+ sub_ctrb = weight * (
+ self.determine_conformance_rate(constraints=constraints_without)
+ - self.determine_conformance_rate(constraints=constraints_with)
+ )
+ sub_ctrbs.append(sub_ctrb)
+ return sum(sub_ctrbs)
+
+ def constraint_ctrb_to_fitness(self, log=None, constraints=None, index=-1):
+ """
+ Determines the Shapley value-based contribution of a constraint to the overall conformance rate.
+
+ :param log: The event log, where keys are strings and values are counts of trace variants.
+ :param constraints: A list of constraints (regexp strings).
+ :param index: The index of the constraint in the constraints list.
+ :return: The contribution of the constraint to the overall conformance rate as a float.
+ """
+ if len(constraints) < index:
+ raise Exception("Constraint not in constraint list.")
+ if not constraints:
+ constraints = self.constraints
+ if index == -1:
+ return f"Add an index for the constraint:\n {constraints}"
+ contributor = constraints[index]
+ ctrb_count = self.check_conformance(contributor, negative=False)
+ len_log = self.get_total_cases()
+ return ctrb_count / (len_log * len(constraints))
+
+ def check_conformance(self, constraint, negative=True):
+ """
+ Checks the conformance of the event log against a specific constraint.
+
+ :param constraint: The constraint to check.
+ :param negative: If negative is true, cases where the constraint is satisfied
+ else, return cases where the constraint is not satisfied.
+ :return: The count of case IDs that match the constraint.
+ """
+ # Formulate the query to count case IDs matching the constraint
+ if negative:
+ query = f'SELECT COUNT(CASE_ID) FROM "defaultview-4" WHERE event_name MATCHES {constraint}'
+ else:
+ query = f'SELECT COUNT(CASE_ID) FROM "defaultview-4" WHERE NOT event_name MATCHES {constraint}'
+ return self.post_query(query) # Execute the query and return the result
+
+ def check_violations(self, constraints):
+ """
+ Checks for violations in the event log against a list of constraints.
+
+ :param constraints: A list of constraints to check for violations.
+ :return: The count of case IDs that violate any of the constraints.
+ """
+ # Combine constraints with OR to find any violations
+ combined_constraints = " OR ".join(
+ [f"NOT event_name MATCHES {constraint}" for constraint in constraints]
+ )
+ query = (
+ f'SELECT COUNT(CASE_ID) FROM "defaultview-4" WHERE {combined_constraints}'
+ )
+ return self.post_query(query) # Execute the query and return the result
+
+ def get_total_cases(self):
+ """
+ Retrieves the total number of cases in the event log.
+
+ :return: The total count of case IDs.
+ """
+ # Query to count all case IDs in the event log
+ query = 'SELECT COUNT(CASE_ID) FROM "defaultview-4"'
+ return self.post_query(query) # Execute the query and return the result
+
+ def post_query(self, query):
+ """
+ Executes a query and returns the result, using caching to optimize repeated queries.
+
+ :param query: The SIGNAL query to execute.
+ :return: The result of the query.
+ """
+ cache_key = hash(query) # Generate a cache key for the query
+ if cache_key in self.cache: # Check if the result is already in the cache
+ return self.cache[cache_key] # Return cached result if available
+
+ # Send the query to the server
+ request = requests.post(
+ self.signal_endpoint,
+ cookies=self.cookies,
+ headers=self.headers,
+ json={"query": query},
+ )
+ result = request.json()["data"][0][0] # Parse the result from the response
+ self.cache[cache_key] = result # Cache the result for future use
+ return result # Return the result
+
+ def post_query_trace_in_dataset(self, trace, constraints):
+ """
+ Checks if a specific trace conforms to given constraints in the dataset.
+
+ :param trace: The trace to check.
+ :param constraints: The constraints to check against. If None, use self.constraints.
+ :return: True if the trace is conformant, False otherwise.
+ """
+ if not constraints:
+ constraints = self.constraints # Use self.constraints if none are provided
+
+ # Combine constraints with AND if there are multiple, otherwise use the single constraint
+ if len(constraints) > 1:
+ constraints = " AND ".join(
+ [f"event_name MATCHES {constraint}" for constraint in constraints]
+ )
+ else:
+ constraints = "".join(f"event_name MATCHES {constraints[0]}")
+
+ # Formulate the query
+ query = (
+ f'SELECT ACTIVITY, COUNT(CASE_ID) FROM "defaultview-4" WHERE {constraints}'
+ )
+
+ cache_key = hash(query) # Generate a cache key for the query
+ if cache_key in self.cache: # Check if the result is already in the cache
+ result = self.cache[cache_key]
+ else:
+ # Send the query to the server and cache the result
+ result = self.post_query_return_all(query)
+ self.cache[cache_key] = result # Cache the result for future use
+
+ # Check if the trace is conformant with any of the results
+ return any(trace.nodes == res[0] for res in result)
+
+ def get_all_conformant_traces(self):
+ """
+ Retrieves all traces that conform to the given constraints.
+
+ :return: A list of conformant traces with their counts.
+ """
+ constraints = self.constraints
+ # Combine constraints with AND if there are multiple, otherwise use the single constraint
+ if len(constraints) > 1:
+ constraints = " AND ".join(
+ [f"event_name MATCHES {constraint}" for constraint in constraints]
+ )
+ else:
+ constraints = "".join(f"event_name MATCHES {constraints[0]}")
+
+ # Formulate the query
+ query = (
+ f'SELECT ACTIVITY, COUNT(CASE_ID) FROM "defaultview-4" WHERE {constraints}'
+ )
+ return self.post_query_return_all(
+ query
+ ) # Execute the query and return the list of conformant traces
+
+ def post_query_return_all(self, query):
+ """
+ Executes a query and returns all results, using caching to optimize repeated queries.
+
+ :param query: The SIGNAL query to execute.
+ :return: All results of the query.
+ """
+ cache_key = hash(query) # Generate a cache key for the query
+ if cache_key in self.cache: # Check if the result is already in the cache
+ return self.cache[cache_key] # Return cached result if available
+
+ # Send the query to the server
+ request = requests.post(
+ self.signal_endpoint,
+ cookies=self.cookies,
+ headers=self.headers,
+ json={"query": query},
+ )
+ result = request.json()["data"] # Parse the result from the response
+ self.cache[cache_key] = result # Cache the result for future use
+ return result # Return the result
+
+ def load_variants(self):
+ """
+ Loads all activity variants from the event log into the event_log attribute.
+
+ :return: None
+ """
+ # Query to retrieve all activity variants
+ query = 'SELECT Activity From "defaultview-4"'
+ data = self.post_query_return_all(query) # Execute the query and get the data
+
+ # Add each activity variant to the event_log
+ for activity in data:
+ self.event_log.add_trace(Trace(activity[0]))
diff --git a/explainer/explainer_util.py b/explainer/explainer_util.py
new file mode 100644
index 0000000..a91f119
--- /dev/null
+++ b/explainer/explainer_util.py
@@ -0,0 +1,357 @@
+from itertools import combinations, chain
+
+
+class Trace:
+ def __init__(self, nodes):
+ """
+ Initializes a Trace instance.
+
+ :param nodes: A list of nodes where each node is represented as a string label.
+ """
+ self.nodes = nodes
+
+ def __len__(self):
+ """
+ Returns the number of nodes in the trace.
+ """
+ return len(self.nodes)
+
+ def __iter__(self):
+ """
+ Initializes the iteration over the nodes in the trace.
+ """
+ self.index = 0
+ return self
+
+ def __next__(self):
+ """
+ Returns the next node in the trace during iteration.
+ """
+ if self.index < len(self.nodes):
+ result = self.nodes[self.index]
+ self.index += 1
+ return result
+ else:
+ raise StopIteration
+
+ def __split__(self):
+ """
+ Splits the nodes of the trace into a list.
+
+ :return: A list containing the nodes of the trace.
+ """
+ spl = []
+ for node in self.nodes:
+ spl.append(node)
+ return spl
+
+
+class EventLog:
+ def __init__(self, trace=None):
+ """
+ Initializes an EventLog instance.
+
+ :param traces: A list of Trace instances.
+ """
+ self.log = {}
+ if trace:
+ self.add_trace(trace)
+
+ def add_trace(self, trace, count=1):
+ """
+ Adds a trace to the log or increments its count if it already exists.
+
+ :param trace: A Trace instance to add.
+ """
+ trace_tuple = tuple(trace.nodes)
+ if trace_tuple in self.log:
+ self.log[trace_tuple] += count
+ else:
+ self.log[trace_tuple] = count
+
+ def remove_trace(self, trace, count=1):
+ """
+ Removes a trace from the log or decrements its count if the count is greater than 1.
+
+ :param trace: A Trace instance to remove.
+ """
+ trace_tuple = tuple(trace.nodes)
+ if trace_tuple in self.log:
+ if self.log[trace_tuple] > count:
+ self.log[trace_tuple] -= count
+ else:
+ del self.log[trace_tuple]
+
+ def get_variant_count(self, trace):
+ """
+ Returns the count of the specified trace in the log.
+
+ :param trace: A Trace instance to check.
+ """
+ trace_tuple = tuple(trace.nodes)
+ return self.log.get(trace_tuple, 0)
+
+ def get_most_frequent_variant(self):
+ """
+ Returns the trace variant with the highest occurrence along with its count.
+
+ :return: A tuple containing the most frequent trace as a Trace instance and its count.
+ """
+ if not self.log:
+ return None, 0 # Return None and 0 if the log is empty
+
+ # Find the trace with the maximum count
+ max_trace_tuple = max(self.log, key=self.log.get)
+ return Trace(list(max_trace_tuple))
+
+ def get_traces(self):
+ """
+ Extracts and returns a list of all unique trace variants in the event log.
+
+ :return: A list of Trace instances, each representing a unique trace.
+ """
+ # Generate a Trace instance for each unique trace tuple in the log
+ return [Trace(list(trace_tuple)) for trace_tuple in self.log.keys()]
+
+ def __str__(self):
+ """
+ Returns a string representation of the event log.
+ """
+ return str(self.log)
+
+ def __len__(self):
+ """
+ Returns the total number of trace occurrences in the log.
+ """
+ return sum(self.log.values())
+
+ def __iter__(self):
+ """
+ Allows iteration over each trace occurrence in the log, sorted by count in descending order.
+ """
+ sorted_log = sorted(self.log.items(), key=lambda item: item[1], reverse=True)
+ for trace_tuple, count in sorted_log:
+ for _ in range(count):
+ yield Trace(list(trace_tuple))
+
+
+def get_sublists(lst):
+ """
+ Generates all possible non-empty sublists of a list.
+
+ :param lst: The input list.
+ :return: A list of all non-empty sublists.
+ """
+ sublists = []
+ for r in range(2, len(lst) + 1): # Generate combinations of length 2 to n
+ sublists.extend(combinations(lst, r))
+ return sublists
+
+
+def levenshtein_distance(seq1, seq2):
+ """
+ Calculates the Levenshtein distance between two sequences.
+
+ Args:
+ seq1 (str): The first sequence.
+ seq2 (str): The second sequence.
+
+ Returns:
+ int: The Levenshtein distance between the two sequences.
+ """
+ size_x = len(seq1) + 1
+ size_y = len(seq2) + 1
+ matrix = [[0] * size_y for _ in range(size_x)]
+ for x in range(size_x):
+ matrix[x][0] = x
+ for y in range(size_y):
+ matrix[0][y] = y
+
+ for x in range(1, size_x):
+ for y in range(1, size_y):
+ if seq1[x - 1] == seq2[y - 1]:
+ matrix[x][y] = matrix[x - 1][y - 1]
+ else:
+ matrix[x][y] = min(
+ matrix[x - 1][y] + 1, matrix[x][y - 1] + 1, matrix[x - 1][y - 1] + 1
+ )
+ return matrix[size_x - 1][size_y - 1]
+
+
+def determine_powerset(elements):
+ """Determines the powerset of a list of elements
+ Args:
+ elements (set): Set of elements
+ Returns:
+ list: Powerset of elements
+ """
+ lset = list(elements)
+ ps_elements = chain.from_iterable(
+ combinations(lset, option) for option in range(len(lset) + 1)
+ )
+ return [set(ps_element) for ps_element in ps_elements]
+
+
+def get_iterative_subtrace(trace):
+ """
+ Generates all possible non-empty contiguous sublists of a list, maintaining order.
+
+ :param lst: The input list.
+ n: the minmum length of sublists
+ :return: A list of all non-empty contiguous sublists.
+ """
+ sublists = []
+ for i in range(0, len(trace)):
+ sublists.append(trace.nodes[0 : i + 1])
+ return sublists
+
+
+SIGNAL_KEYWORDS = [
+ "ABS",
+ "ALL",
+ "ANALYZE",
+ "AND",
+ "ANY",
+ "AS",
+ "ASC",
+ "AVG",
+ "BARRIER",
+ "BEHAVIOUR",
+ "BETWEEN",
+ "BOOL_AND",
+ "BOOL_OR",
+ "BUCKET",
+ "BY",
+ "CASE",
+ "CASE_ID",
+ "CATEGORY",
+ "CEIL",
+ "CHAR_INDEX",
+ "CHAR_LENGTH",
+ "COALESCE",
+ "CONCAT",
+ "COUNT",
+ "CREATE",
+ "CURRENT",
+ "DATE_ADD",
+ "DATE_DIFF",
+ "DATE_PART",
+ "DATE_TRUNC",
+ "DEFAULT",
+ "DENSE_RANK",
+ "DESC",
+ "DESCRIBE",
+ "DISTINCT",
+ "DROP",
+ "DURATION",
+ "DURATION_BETWEEN",
+ "DURATION_FROM_DAYS",
+ "DURATION_FROM_MILLISECONDS",
+ "DURATION_TO_DAYS",
+ "DURATION_TO_MILLISECONDS",
+ "ELSE",
+ "END",
+ "END_TIME",
+ "EVENT_ID",
+ "EVENT_NAME",
+ "EVENTS",
+ "EXACT",
+ "EXPLAIN",
+ "EXTERNAL",
+ "FALSE",
+ "FILL",
+ "FILTER",
+ "FIRST",
+ "FLATTEN",
+ "FLOOR",
+ "FOLLOWING",
+ "FORMAT",
+ "FROM",
+ "GRANT",
+ "GROUP",
+ "HAVING",
+ "IF",
+ "ILIKE",
+ "IN",
+ "INVOKER",
+ "IS",
+ "JOIN",
+ "JSON",
+ "LAG",
+ "LAST",
+ "LEAD",
+ "LEFT",
+ "LIKE",
+ "LIMIT",
+ "LOCATION",
+ "LOG",
+ "MATCHES",
+ "MAX",
+ "MEDIAN",
+ "MIN",
+ "NOT",
+ "NOW",
+ "NULL",
+ "NULLS",
+ "OCCURRENCE",
+ "ODATA",
+ "OFFSET",
+ "ON",
+ "ONLY",
+ "OR",
+ "ORDER",
+ "OUTER",
+ "OVER",
+ "PARQUET",
+ "PARTITION",
+ "PERCENT",
+ "PERCENTILE_CONT",
+ "PERCENTILE_DESC",
+ "PERMISSIONS",
+ "POW",
+ "PRECEDING",
+ "PRIVATE",
+ "PUBLIC",
+ "RANGE",
+ "RANK",
+ "REGR_INTERCEPT",
+ "REGR_SLOPE",
+ "REPEATABLE",
+ "REPLACE",
+ "RIGHT",
+ "ROUND",
+ "ROW",
+ "ROW_NUMBER",
+ "ROWS",
+ "SECURITY",
+ "SELECT",
+ "SIGN",
+ "SQRT",
+ "START_TIME",
+ "STDDEV",
+ "SUBSTRING",
+ "SUBSTRING_AFTER",
+ "SUBSTRING_BEFORE",
+ "SUM",
+ "TABLE",
+ "TABULAR",
+ "TEXT",
+ "THEN",
+ "TIMESERIES",
+ "TIMESTAMP",
+ "TO",
+ "TO_NUMBER",
+ "TO_STRING",
+ "TO_TIMESTAMP",
+ "TRUE",
+ "TRUNC",
+ "UNBOUNDED",
+ "UNION",
+ "USING",
+ "VIEW",
+ "WHEN",
+ "WHERE",
+ "WITH",
+ "WITHIN",
+ "",
+]
diff --git a/setup.py b/setup.py
index dffd6fe..2882653 100644
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,5 @@
"""Setup for running the bpmnconstraints script."""
+
import setuptools
with open("README.md", encoding="utf-8") as file:
diff --git a/tests/explainer/explainer_test.py b/tests/explainer/explainer_test.py
new file mode 100644
index 0000000..db931bc
--- /dev/null
+++ b/tests/explainer/explainer_test.py
@@ -0,0 +1,262 @@
+from explainer.explainer_regex import ExplainerRegex
+from explainer.explainer_util import Trace, EventLog
+
+
+# Test 1: Adding and checking constraints
+def test_add_constraint():
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B.*C")
+ assert "A.*B.*C" in explainer.constraints, "Constraint 'A.*B.*C' should be added."
+
+
+# Test 2: Removing constraints
+def test_remove_constraint():
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B.*C")
+ explainer.add_constraint("B.*C")
+ explainer.remove_constraint(0)
+ assert (
+ "A.*B.*C" not in explainer.constraints
+ ), "Constraint 'A.*B.*C' should be removed."
+
+
+# Test 3: Activation of constraints
+def test_activation():
+ trace = Trace(["A", "B", "C"])
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B.*C")
+ assert explainer.activation(trace), "The trace should activate the constraint."
+
+
+# Test 4: Checking conformance of traces
+def test_conformance():
+ trace = Trace(["A", "B", "C"])
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B.*C")
+ assert explainer.conformant(trace), "The trace should be conformant."
+
+
+# Test 5: Non-conformance explanation
+def test_non_conformance_explanation():
+ trace = Trace(["C", "A", "B"])
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B.*C")
+ explanation = explainer.minimal_expl(trace)
+ assert "violated" in explanation, "The explanation should indicate a violation."
+
+
+# Test 6: Overlapping constraints
+def test_overlapping_constraints():
+ trace = Trace(["A", "B", "A", "C"])
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B.*C")
+ explainer.add_constraint("A.*A.*C")
+ assert explainer.conformant(
+ trace
+ ), "The trace should be conformant with overlapping constraints."
+
+
+# Test 7: Partially meeting constraints
+def test_partial_conformance():
+ trace = Trace(["A", "C", "B"])
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B.*C")
+ assert not explainer.conformant(trace), "The trace should not be fully conformant."
+
+
+# Test 8: Constraints with repeated nodes
+def test_constraints_with_repeated_nodes():
+ trace = Trace(["A", "A", "B", "A"])
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*A.*B.*A")
+ assert explainer.conformant(
+ trace
+ ), "The trace should conform to the constraint with repeated nodes."
+
+
+# Test 9: Removing constraints and checking nodes list
+def test_remove_constraint_and_check_nodes():
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B")
+ explainer.add_constraint("B.*C")
+ explainer.remove_constraint(0)
+ assert (
+ "A" not in explainer.nodes and "B" in explainer.nodes and "C" in explainer.nodes
+ ), "Node 'A' should be removed, while 'B' and 'C' remain."
+
+
+# Test 10: Complex regex constraint
+def test_complex_regex_constraint():
+ trace = Trace(["A", "X", "B", "Y", "C"])
+ explainer = ExplainerRegex()
+ explainer.add_constraint(
+ "A.*X.*B.*Y.*C"
+ ) # Specifically expects certain nodes in order
+ assert explainer.conformant(
+ trace
+ ), "The trace should conform to the complex regex constraint."
+
+
+# Test 11: Constraint not covered by any trace node
+def test_constraint_not_covered():
+ trace = Trace(["A", "B", "C"])
+ explainer = ExplainerRegex()
+ explainer.add_constraint("D*") # This node "D" does not exist in the trace
+ assert explainer.activation(trace) == [
+ 0
+ ], "The constraint should not be activated by the trace."
+
+
+# Test 12: Empty trace and constraints
+def test_empty_trace_and_constraints():
+ trace = Trace([])
+ explainer = ExplainerRegex()
+ explainer.add_constraint("") # Adding an empty constraint
+ assert explainer.conformant(
+ trace
+ ), "An empty trace should be conformant with an empty constraint."
+
+
+# Test 13: Removing non-existent constraint index
+def test_remove_nonexistent_constraint():
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B")
+ explainer.remove_constraint(10) # Non-existent index
+ assert (
+ len(explainer.constraints) == 1
+ ), "Removing a non-existent constraint should not change the constraints list."
+
+
+# Test 14: Activation with no constraints
+def test_activation_with_no_constraints():
+ trace = Trace(["A", "B", "C"])
+ explainer = ExplainerRegex()
+ assert not explainer.activation(trace), "No constraints should mean no activation."
+
+
+# Test 15: Trace conformance against multiple constraints
+def test_trace_conformance_against_multiple_constraints():
+ trace1 = Trace(
+ ["A", "B", "D"]
+ ) # This trace should not be fully conformant as it only matches one constraint
+ trace2 = Trace(
+ ["A", "B", "C", "D"]
+ ) # This trace should be conformant as it matches both constraints
+
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B.*C") # Both traces attempt to conform to this
+ explainer.add_constraint("B.*D") # And to this
+
+ # Checking conformance
+ assert not explainer.conformant(
+ trace1
+ ), "Trace1 should not be conformant as it does not satisfy all constraints."
+ assert explainer.conformant(
+ trace2
+ ), "Trace2 should be conformant as it satisfies all constraints."
+
+
+# Test 16: Conformant trace does not generate minimal explaination
+def test_conformant_trace_handled_correctly():
+ trace = Trace(["A", "B"])
+ explainer = ExplainerRegex()
+ explainer.add_constraint("AB")
+
+ assert (
+ explainer.minimal_expl(trace)
+ == "The trace is already conformant, no changes needed."
+ )
+
+
+# Test 17: Conformant trace
+def test_explainer_methods():
+ trace = Trace(["A", "B", "C"])
+ explainer = ExplainerRegex()
+ explainer.add_constraint("A.*B.*C")
+ explainer.add_constraint("B.*C")
+
+ assert (
+ explainer.conformant(trace) == True
+ ), "Test 1 Failed: Trace should be conformant."
+ assert (
+ explainer.minimal_expl(trace)
+ == "The trace is already conformant, no changes needed."
+ ), "Test 1 Failed: Incorrect minimal explanation for a conformant trace."
+ assert (
+ explainer.counterfactual_expl(trace)
+ == "The trace is already conformant, no changes needed."
+ ), "Test 1 Failed: Incorrect counterfactual explanation for a conformant trace."
+
+
+# Test 18: Some explaination test
+def test_explaination():
+ explainer = ExplainerRegex()
+
+ conformant_trace = Trace(["A", "B", "C"])
+ non_conformant_trace = Trace(["A", "C"])
+
+ explainer.add_constraint("A.*B.*C")
+
+ assert explainer.conformant(non_conformant_trace) == False
+ assert explainer.conformant(conformant_trace) == True
+ assert (
+ explainer.minimal_expl(non_conformant_trace)
+ == "Non-conformance due to: Constraint (A.*B.*C) is violated by subtrace: ('A', 'C')"
+ )
+ assert (
+ explainer.counterfactual_expl(non_conformant_trace)
+ == "\nAddition (Added B at position 1): A->B->C"
+ )
+
+
+# Test 19: Complex explaination test.
+"""
+This part is not very complex as of now and is very much up for change, the complexity of counterfactuals
+proved to be slightly larger than expected
+"""
+
+
+def test_complex_counterfactual_explanation():
+ explainer = ExplainerRegex()
+
+ explainer.add_constraint("ABB*C")
+
+ non_conformant_trace = Trace(["A", "C", "E", "D"])
+
+ counterfactual_explanation = explainer.counterfactual_expl(non_conformant_trace)
+
+ assert (
+ counterfactual_explanation
+ == "\nAddition (Added B at position 1): A->B->C->E->D"
+ )
+
+
+# Test 20: Event logs
+def test_event_log():
+ event_log = EventLog()
+ assert event_log != None
+ trace = Trace(["A", "B", "C"])
+ event_log.add_trace(trace)
+ assert event_log.log == {
+ ("A", "B", "C"): 1
+ } # There should be one instance of the trace in the log
+ event_log.add_trace(trace, 5)
+ assert event_log.log == {
+ ("A", "B", "C"): 6
+ } # There should be 6 instances of the trace in the log
+ event_log.remove_trace(trace)
+ assert event_log.log == {
+ ("A", "B", "C"): 5
+ } # There should be 5 instances of the trace
+ event_log.remove_trace(trace, 5)
+ assert event_log.log == {} # The log should be emptied
+ event_log.add_trace(trace, 5)
+ event_log.remove_trace(trace, 10)
+ assert event_log.log == {} # The log should be emptied
+ trace2 = Trace(["X", "Y", "Z"])
+ event_log.add_trace(trace, 5)
+ event_log.add_trace(trace2, 7)
+ assert event_log.log == {
+ ("A", "B", "C"): 5,
+ ("X", "Y", "Z"): 7,
+ } # There should be several traces in the log
diff --git a/tests/file_constants.py b/tests/file_constants.py
index cd52d64..31331ca 100644
--- a/tests/file_constants.py
+++ b/tests/file_constants.py
@@ -1,12 +1,6 @@
LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END = {
"path": "examples/linear/linear_sequence.json",
- "start element id": "sid-79912385-C358-446C-8EBB-07429B015548",
- "end element id": "sid-BEA0DEB9-2482-42D9-9846-9E6C5541FA54",
- "successor id": "sid-338230CF-C52B-4C83-9B4E-A8388E336593",
-}
-
-LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END_XML = {
- "path": "examples/xml/Invoice processing.xml",
+ "xmlpath": "examples/linear/linear_sequence.xml",
"start element id": "sid-79912385-C358-446C-8EBB-07429B015548",
"end element id": "sid-BEA0DEB9-2482-42D9-9846-9E6C5541FA54",
"successor id": "sid-338230CF-C52B-4C83-9B4E-A8388E336593",
@@ -14,12 +8,14 @@
LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END = {
"path": "examples/misc/no_start_no_end.json",
+ "xmlpath": "examples/misc/no_start_no_end.xml",
"start element id": "sid-E9508543-5660-4C85-9E42-1119DAAD80C2",
"end element id": "sid-08543ADB-C8D6-4026-8A03-1228CC559A7F",
}
MULTIPLE_STARTS_DIAGRAM = {
"path": "examples/misc/multiple_starts.json",
+ "xmlpath": "examples/misc/multiple_starts.xml",
"start elements": [
"sid-63552E64-B2A2-4D39-A168-2C6A30BB76F7",
"sid-AB69BFC4-A028-480F-BC16-BAC74F4A8EDD",
@@ -28,6 +24,7 @@
MULTIPLE_ENDINGS_DIAGRAM = {
"path": "examples/misc/multiple_endings.json",
+ "xmlpath": "examples/misc/multiple_endings.xml",
"ending elements": [
"sid-F54D1372-E982-4B0F-9543-F3CC3C6F595F",
"sid-42CD2A75-895E-4E2C-9340-6CE7C5570EFF",
@@ -37,12 +34,14 @@
SINGLE_XOR_GATEWAY_DIAGRAM = {
"path": "examples/xor_gates/single_xor.json",
+ "xmlpath": "examples/xor_gates/single_xor.xml",
"splitting id": "sid-E1967D7F-6A3B-40CB-A8E9-31606735C37A",
"joining id": "sid-87FDC0D7-9BEE-4FB2-952A-FEDEA56F73AA",
}
THREE_SPLIT_XOR_GATEWAY_DIAGRAM = {
"path": "examples/xor_gates/3_way_split_xor.json",
+ "xmlpath": "examples/xor_gates/3_way_split_xor.xml",
"splitting id": "sid-7946CDE8-E0E9-4730-8D59-E48E15C331B8",
"successors": [
"sid-DEEAF1CC-6862-41BE-8FE4-C9630A72A6E7",
@@ -53,6 +52,7 @@
PARALLEL_GATEWAY_DIAGRAM = {
"path": "examples/and_gates/longer_and.json",
+ "xmlpath": "examples/and_gates/longer_and.xml",
"start element id": "sid-2FE6222A-6971-4860-AD8D-535CED93A0A2",
"ending element id": "sid-41F52A20-F3FC-4363-9A0C-A73114841060",
"gateway elements": [
@@ -69,18 +69,26 @@
],
}
-XOR_GATEWAY_DIAGRAM = {"path": "examples/xor_gates/longer_xor.json"}
+XOR_GATEWAY_DIAGRAM = {
+ "path": "examples/xor_gates/longer_xor.json",
+ "xmlpath": "examples/xor_gates/longer_xor.xml",
+}
-XOR_GATEWAY_SEQUENCE_DIAGRAM = {"path": "examples/xor_gates/multiple_xor.json"}
+XOR_GATEWAY_SEQUENCE_DIAGRAM = {
+ "path": "examples/xor_gates/multiple_xor.json",
+ "xmlpath": "examples/xor_gates/multiple_xor.xml",
+}
REQUIREMENTS_TXT = {"path": "requirements.txt"}
LINEAR_MERMAID_GRAPH = {
"path": "examples/linear/linear_sequence.json",
+ "xmlpath": "examples/linear/linear_sequence.xml",
"output": "flowchart LR\n0:startnoneevent:((start))-->1:task:(register invoice)\n1:task:-->2:task:(check invoice)\n2:task:-->3:task:(accept invoice)\n3:task:-->4:endnoneevent:((end))",
}
GATEWAY_MERMAID_GRAPH = {
"path": "examples/xor_gates/single_xor.json",
+ "xmlpath": "examples/xor_gates/single_xor.xml",
"output": "flowchart LR\n0:exclusive_databased_gateway:{XOR}-->1:task:(second activity)\n0:exclusive_databased_gateway:{XOR}-->2:task:(first activity)\n3:exclusive_databased_gateway:{XOR}-->4:task:(third activity)\n2:task:-->3:exclusive_databased_gateway:\n1:task:-->3:exclusive_databased_gateway:\n4:task:-->5:endnoneevent:((endnoneevent))\n6:startnoneevent:((startnoneevent))-->7:task:(zero activity)\n7:task:-->0:exclusive_databased_gateway:",
}
diff --git a/tests/test_end_constraints.py b/tests/test_end_constraints.py
index 8b80d84..ef7ad85 100644
--- a/tests/test_end_constraints.py
+++ b/tests/test_end_constraints.py
@@ -27,14 +27,39 @@ def test_end_constraint_is_generated_without_explicit_end_event():
assert "End[second element]" in res
-def test_end_constraint_is_generated_when_multiple_endings():
- res = init_test_setup_for_parser(XOR_GATEWAY_SEQUENCE_DIAGRAM)
+def test_end_constraint_is_generated_when_xor_gateway():
+ res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM)
+ expected_ending_constraints = [
+ "End[activity four]",
+ "End[activity five]",
+ ]
+ assert all(constraint in res for constraint in expected_ending_constraints)
- assert res[-1]["is end"] and res[-2]["is end"] and not res[3]["is end"]
+def test_end_constraint_is_generated_when_multiple_endings_XML():
+ res = init_test_setup_for_compiler(MULTIPLE_ENDINGS_DIAGRAM, test_xml=True)
+ expected_ending_constraints = [
+ "End[ending one]",
+ "End[ending two]",
+ "End[ending three]",
+ ]
+ assert all(constraint in res for constraint in expected_ending_constraints)
-def test_end_constraint_is_generated_when_xor_gateway():
- res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM)
+
+def test_end_constraint_is_generated_with_linear_parser_XML():
+ res = init_test_setup_for_parser(LINEAR_MERMAID_GRAPH, test_xml=True)
+ assert res[-1]["is end"] == True
+
+
+def test_end_constraint_is_generated_without_explicit_end_event_XML():
+ res = init_test_setup_for_compiler(
+ LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END, test_xml=True
+ )
+ assert "End[second element]" in res
+
+
+def test_end_constraint_is_generated_when_xor_gateway_XML():
+ res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM, test_xml=True)
expected_ending_constraints = [
"End[activity four]",
"End[activity five]",
diff --git a/tests/test_gateway_constraints.py b/tests/test_gateway_constraints.py
index 744460c..7d100d1 100644
--- a/tests/test_gateway_constraints.py
+++ b/tests/test_gateway_constraints.py
@@ -11,3 +11,13 @@ def test_that_all_gateway_constraints_are_generated():
]
# assert res == expected_gateway_constraints
assert all(constraint in res for constraint in expected_gateway_constraints)
+
+
+def test_that_all_gateway_constraints_are_generated_XML():
+ res = init_test_setup_for_compiler(THREE_SPLIT_XOR_GATEWAY_DIAGRAM, True)
+ expected_gateway_constraints = [
+ "Exclusive Choice[activity four, activity two]",
+ "Exclusive Choice[activity three, activity two]",
+ "Exclusive Choice[activity three, activity four]",
+ ]
+ assert all(constraint in res for constraint in expected_gateway_constraints)
diff --git a/tests/test_gateway_splitting_joining.py b/tests/test_gateway_splitting_joining.py
index 534a10e..b0aa46c 100644
--- a/tests/test_gateway_splitting_joining.py
+++ b/tests/test_gateway_splitting_joining.py
@@ -24,3 +24,27 @@ def test_gateway_splitting_to_three_paths():
assert sorted(successors_id) == sorted(
THREE_SPLIT_XOR_GATEWAY_DIAGRAM.get("successors")
)
+
+
+def test_element_is_marked_as_splitting_gateway_if_it_is_splitting_xml():
+ res = init_test_setup_for_parser(SINGLE_XOR_GATEWAY_DIAGRAM, True)
+ for elem in res:
+ if elem.get("id") == SINGLE_XOR_GATEWAY_DIAGRAM.get("splitting id"):
+ assert elem.get("splitting")
+
+
+def test_element_is_marked_as_joining_gateway_if_it_is_joining_xml():
+ res = init_test_setup_for_parser(SINGLE_XOR_GATEWAY_DIAGRAM, True)
+ for elem in res:
+ if elem.get("id") == SINGLE_XOR_GATEWAY_DIAGRAM.get("joining id"):
+ assert elem.get("joining")
+
+
+def test_gateway_splitting_to_three_paths_xml():
+ res = init_test_setup_for_parser(THREE_SPLIT_XOR_GATEWAY_DIAGRAM, True)
+ for elem in res:
+ if elem.get("id") == THREE_SPLIT_XOR_GATEWAY_DIAGRAM.get("splitting id"):
+ successors_id = [x.get("id") for x in elem.get("successor")]
+ assert sorted(successors_id) == sorted(
+ THREE_SPLIT_XOR_GATEWAY_DIAGRAM.get("successors")
+ )
diff --git a/tests/test_init_constraints.py b/tests/test_init_constraints.py
index 247776b..131603d 100644
--- a/tests/test_init_constraints.py
+++ b/tests/test_init_constraints.py
@@ -29,3 +29,30 @@ def test_missing_init_constraints_for_XOR_gate():
"Init[activity two]",
]
assert all(constraint in res for constraint in expected_init_constraints)
+
+
+def test_init_constraint_is_generated_without_explicit_start_event_xml():
+ res = init_test_setup_for_compiler(
+ LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END, True
+ )
+ assert "Init[first element]" in res
+
+
+def test_that_each_start_has_init_constraint_xml():
+ res = init_test_setup_for_compiler(MULTIPLE_STARTS_DIAGRAM, True)
+ expected_init_constraints = ["Init[path one]", "Init[path two]"]
+ assert all(constraint in res for constraint in expected_init_constraints)
+
+
+def test_missing_init_constraints_for_XOR_gate_parser_xml():
+ res = init_test_setup_for_parser(XOR_GATEWAY_SEQUENCE_DIAGRAM, True)
+ assert res[4]["is start"] and res[5]["is start"] and not res[0]["is start"]
+
+
+def test_missing_init_constraints_for_XOR_gate_xml():
+ res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM, True)
+ expected_init_constraints = [
+ "Init[activity one]",
+ "Init[activity two]",
+ ]
+ assert all(constraint in res for constraint in expected_init_constraints)
diff --git a/tests/test_is_end.py b/tests/test_is_end.py
index b721004..0eb58a2 100644
--- a/tests/test_is_end.py
+++ b/tests/test_is_end.py
@@ -34,3 +34,34 @@ def test_all_start_elements_are_marked_as_ending_if_multiple_endings():
):
end_count += 1
assert end_count == len(MULTIPLE_ENDINGS_DIAGRAM.get("ending elements"))
+
+
+def test_element_is_marked_as_end_if_it_has_no_successors_xml():
+ res = init_test_setup_for_parser(
+ LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END, True
+ )
+ for elem in res:
+ if elem.get("is end"):
+ assert elem.get("id") == LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END.get(
+ "end element id"
+ )
+
+
+def test_element_is_marked_as_end_if_successor_is_end_event_xml():
+ res = init_test_setup_for_parser(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, True)
+ for elem in res:
+ if elem.get("is end"):
+ assert elem.get("id") == LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END.get(
+ "end element id"
+ )
+
+
+def test_all_start_elements_are_marked_as_ending_if_multiple_endings_xml():
+ res = init_test_setup_for_parser(MULTIPLE_ENDINGS_DIAGRAM, True)
+ end_count = 0
+ for elem in res:
+ if elem.get("is end") and elem.get("id") in MULTIPLE_ENDINGS_DIAGRAM.get(
+ "ending elements"
+ ):
+ end_count += 1
+ assert end_count == len(MULTIPLE_ENDINGS_DIAGRAM.get("ending elements"))
diff --git a/tests/test_is_start.py b/tests/test_is_start.py
index 139d7d0..22c5e75 100644
--- a/tests/test_is_start.py
+++ b/tests/test_is_start.py
@@ -34,3 +34,34 @@ def test_all_start_elements_are_marked_as_starts_if_multiple_starts():
):
start_count += 1
assert start_count == len(MULTIPLE_STARTS_DIAGRAM.get("start elements"))
+
+
+def test_element_is_marked_as_start_if_it_has_no_predecessors_xml():
+ res = init_test_setup_for_parser(
+ LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END, True
+ )
+ for elem in res:
+ if elem.get("is start"):
+ assert elem.get("id") == LINEAR_SEQUENCE_DIAGRAM_WITHOUT_START_AND_END.get(
+ "start element id"
+ )
+
+
+def test_element_is_marked_as_start_if_predecessor_is_start_event_xml():
+ res = init_test_setup_for_parser(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, True)
+ for elem in res:
+ if elem.get("is start"):
+ assert elem.get("id") == LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END.get(
+ "start element id"
+ )
+
+
+def test_all_start_elements_are_marked_as_starts_if_multiple_starts_xml():
+ res = init_test_setup_for_parser(MULTIPLE_STARTS_DIAGRAM, True)
+ start_count = 0
+ for elem in res:
+ if elem.get("is start") and elem.get("id") in MULTIPLE_STARTS_DIAGRAM.get(
+ "start elements"
+ ):
+ start_count += 1
+ assert start_count == len(MULTIPLE_STARTS_DIAGRAM.get("start elements"))
diff --git a/tests/test_part_of_gateway.py b/tests/test_part_of_gateway.py
index 067e623..c49a5d5 100644
--- a/tests/test_part_of_gateway.py
+++ b/tests/test_part_of_gateway.py
@@ -20,3 +20,23 @@ def test_element_outside_gateway_construct_is_not_marked_as_part_of_gateway():
assert num_elems_not_in_gateway == len(
PARALLEL_GATEWAY_DIAGRAM.get("not gateway elements")
)
+
+
+def test_element_in_gateway_construct_is_marked_as_part_of_gateway_xml():
+ res = init_test_setup_for_parser(PARALLEL_GATEWAY_DIAGRAM, True)
+ num_elems_in_gateway = 0
+ for elem in res:
+ if elem.get("id") in PARALLEL_GATEWAY_DIAGRAM.get("gateway elements"):
+ num_elems_in_gateway += 1
+ assert num_elems_in_gateway == len(PARALLEL_GATEWAY_DIAGRAM.get("gateway elements"))
+
+
+def test_element_outside_gateway_construct_is_not_marked_as_part_of_gateway_xml():
+ res = init_test_setup_for_parser(PARALLEL_GATEWAY_DIAGRAM, True)
+ num_elems_not_in_gateway = 0
+ for elem in res:
+ if elem.get("id") in PARALLEL_GATEWAY_DIAGRAM.get("not gateway elements"):
+ num_elems_not_in_gateway += 1
+ assert num_elems_not_in_gateway == len(
+ PARALLEL_GATEWAY_DIAGRAM.get("not gateway elements")
+ )
diff --git a/tests/test_precedence_constraints.py b/tests/test_precedence_constraints.py
index 6250329..cb58b54 100644
--- a/tests/test_precedence_constraints.py
+++ b/tests/test_precedence_constraints.py
@@ -22,3 +22,25 @@ def test_precedence_constraint_is_generated_for_element_between_two_gateway_cons
"Alternate Precedence[activity three, activity five]",
]
assert all(constraint in res for constraint in expected_precedence_constraints)
+
+
+def test_precedence_constraint_is_generated_for_splitting_gateway_xml():
+ res = init_test_setup_for_compiler(XOR_GATEWAY_DIAGRAM, True)
+ expected_precedence_constraints = [
+ "Precedence[first activity, second activity upper]",
+ "Precedence[first activity, second activity lower]",
+ "Alternate Precedence[first activity, second activity upper]",
+ "Alternate Precedence[first activity, second activity lower]",
+ ]
+ assert all(constraint in res for constraint in expected_precedence_constraints)
+
+
+def test_precedence_constraint_is_generated_for_element_between_two_gateway_constructs_xml():
+ res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM, True)
+ expected_precedence_constraints = [
+ "Precedence[activity three, activity four]",
+ "Precedence[activity three, activity five]",
+ "Alternate Precedence[activity three, activity four]",
+ "Alternate Precedence[activity three, activity five]",
+ ]
+ assert all(constraint in res for constraint in expected_precedence_constraints)
diff --git a/tests/test_response_constraint.py b/tests/test_response_constraint.py
index dbbeb05..f103784 100644
--- a/tests/test_response_constraint.py
+++ b/tests/test_response_constraint.py
@@ -22,3 +22,25 @@ def test_response_constraint_is_generated_for_element_between_two_gateway_constr
"Alternate Response[activity two, activity three]",
]
assert all(constraint in res for constraint in expected_response_constraints)
+
+
+def test_response_constraint_is_generated_for_joining_gateway_xml():
+ res = init_test_setup_for_compiler(XOR_GATEWAY_DIAGRAM, True)
+ expected_response_constraints = [
+ "Response[forth activity upper, last activity]",
+ "Response[forth activity lower, last activity]",
+ "Alternate Response[forth activity upper, last activity]",
+ "Alternate Response[forth activity lower, last activity]",
+ ]
+ assert all(constraint in res for constraint in expected_response_constraints)
+
+
+def test_response_constraint_is_generated_for_element_between_two_gateway_constructs_xml():
+ res = init_test_setup_for_compiler(XOR_GATEWAY_SEQUENCE_DIAGRAM, True)
+ expected_response_constraints = [
+ "Response[activity one, activity three]",
+ "Response[activity two, activity three]",
+ "Alternate Response[activity one, activity three]",
+ "Alternate Response[activity two, activity three]",
+ ]
+ assert all(constraint in res for constraint in expected_response_constraints)
diff --git a/tests/test_sequential_flow.py b/tests/test_sequential_flow.py
index 01fa365..3463b1a 100644
--- a/tests/test_sequential_flow.py
+++ b/tests/test_sequential_flow.py
@@ -60,3 +60,44 @@ def test_no_co_existence_between_element_and_gateway_element():
assert "Co-Existence[zero Activity, first Activity]" not in res
assert "Co-Existence[first Activity, zero Activity]" not in res
+
+
+def test_choice_constraints_generated_for_sequential_flow_xml():
+ res = init_test_setup_for_compiler(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, True)
+ expected_choice_constraints = [
+ "Choice[check invoice, register invoice]",
+ "Choice[accept invoice, check invoice]",
+ ]
+ assert all(constraint in res for constraint in expected_choice_constraints)
+
+
+def test_succession_constraints_generated_for_sequential_flow_xml():
+ res = init_test_setup_for_compiler(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, True)
+ expected_succession_constraints = [
+ "Succession[register invoice, check invoice]",
+ "Succession[check invoice, accept invoice]",
+ ]
+ assert all(constraint in res for constraint in expected_succession_constraints)
+
+
+def test_co_existence_constraints_generated_for_sequential_flow_xml():
+ res = init_test_setup_for_compiler(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, True)
+ expected_co_existence_constraints = [
+ "Co-Existence[check invoice, register invoice]",
+ "Co-Existence[accept invoice, check invoice]",
+ ]
+ assert all(constraint in res for constraint in expected_co_existence_constraints)
+
+
+def test_no_succession_between_element_and_gateway_element_xml():
+ res = init_test_setup_for_compiler(SINGLE_XOR_GATEWAY_DIAGRAM, True)
+
+ assert "Succession[zero Activity, first Activity]" not in res
+ assert "Succession[zero Activity, second Activity]" not in res
+
+
+def test_no_co_existence_between_element_and_gateway_element_xml():
+ res = init_test_setup_for_compiler(SINGLE_XOR_GATEWAY_DIAGRAM)
+
+ assert "Co-Existence[zero Activity, first Activity]" not in res
+ assert "Co-Existence[first Activity, zero Activity]" not in res
diff --git a/tests/test_transitivity.py b/tests/test_transitivity.py
index 2b88483..3becda1 100644
--- a/tests/test_transitivity.py
+++ b/tests/test_transitivity.py
@@ -22,3 +22,22 @@ def test_transative_closure_between_elements_before_and_after_gateway_construct(
if elem.get("is start"):
transitive_elems = [x.get("id") for x in elem.get("transitivity")]
assert PARALLEL_GATEWAY_DIAGRAM.get("ending element id") in transitive_elems
+
+
+def test_successor_is_also_in_transative_closure_xml():
+ res = init_test_setup_for_parser(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, True)
+ for elem in res:
+ if elem.get("is start"):
+ transitive_elems = [x.get("id") for x in elem.get("transitivity")]
+ assert (
+ LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END.get("successor id")
+ in transitive_elems
+ )
+
+
+def test_transative_closure_between_elements_before_and_after_gateway_construct_xml():
+ res = init_test_setup_for_parser(PARALLEL_GATEWAY_DIAGRAM, True)
+ for elem in res:
+ if elem.get("is start"):
+ transitive_elems = [x.get("id") for x in elem.get("transitivity")]
+ assert PARALLEL_GATEWAY_DIAGRAM.get("ending element id") in transitive_elems
diff --git a/tests/test_utils.py b/tests/test_utils.py
index c3a4945..7758048 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -5,16 +5,16 @@
from bpmnconstraints.mermaid.mermaidtranslation import Mermaid
-def init_test_setup_for_parser(diagram_constant):
- path = Path(diagram_constant.get("path"))
+def init_test_setup_for_parser(diagram_constant, test_xml=False):
+ path = Path(diagram_constant["xmlpath" if test_xml else "path"])
setup = Setup(None)
if setup.is_file(path):
res = Parser(path, True, True).run()
return res
-def init_test_setup_for_compiler(diagram_constant):
- path = Path(diagram_constant.get("path"))
+def init_test_setup_for_compiler(diagram_constant, test_xml=False):
+ path = Path(diagram_constant["xmlpath" if test_xml else "path"])
constraints = []
setup = Setup(None)
if setup.is_file(path):
@@ -25,8 +25,8 @@ def init_test_setup_for_compiler(diagram_constant):
return constraints
-def init_test_setup_for_mermaid(diagram_constant):
- path = Path(diagram_constant.get("path"))
+def init_test_setup_for_mermaid(diagram_constant, test_xml=False):
+ path = Path(diagram_constant["xmlpath" if test_xml else "path"])
setup = Setup(None)
if setup.is_file(path):
bpmn = Parser(path, True, False).run()
diff --git a/tests/test_xml_file.py b/tests/test_xml_file.py
index f84a2c8..73e1160 100644
--- a/tests/test_xml_file.py
+++ b/tests/test_xml_file.py
@@ -1,17 +1,16 @@
from json import JSONDecodeError
from pytest import raises
from file_constants import (
- LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END_XML,
LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END,
REQUIREMENTS_TXT,
)
-from test_utils import init_test_setup_for_compiler
+from test_utils import init_test_setup_for_compiler, init_test_setup_for_parser
def test_xml_file_is_identified():
try:
xml = init_test_setup_for_compiler(
- LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END_XML
+ LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, test_xml=True
)
except JSONDecodeError:
assert False
@@ -19,11 +18,33 @@ def test_xml_file_is_identified():
def test_unsupported_file_extension_is_rejected():
with raises(Exception):
- xml = init_test_setup_for_compiler(REQUIREMENTS_TXT)
+ xml = init_test_setup_for_compiler(REQUIREMENTS_TXT, False)
+
+
+def are_dicts_equal(dict1, dict2, attribute_to_compare):
+ if len(dict1) != len(dict2):
+ return False
+
+ for item1, item2 in zip(dict1, dict2):
+ if item1[attribute_to_compare] != item2[attribute_to_compare]:
+ return False
+
+ return True
def test_that_xml_and_json_parsing_generates_same_output():
+ json_data = init_test_setup_for_parser(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END)
+ xml_data = init_test_setup_for_parser(
+ LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, test_xml=True
+ )
+
+ assert are_dicts_equal(json_data, xml_data, "name")
+
+
+def test_that_xml_and_json_compiling_generates_same_output():
json = init_test_setup_for_compiler(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END)
- xml = init_test_setup_for_compiler(LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END_XML)
+ xml = init_test_setup_for_compiler(
+ LINEAR_SEQUENCE_DIAGRAM_WITH_START_AND_END, test_xml=True
+ )
assert sorted(json) == sorted(xml)
diff --git a/tutorial/explainer_tutorial_1.ipynb b/tutorial/explainer_tutorial_1.ipynb
new file mode 100644
index 0000000..c92d27d
--- /dev/null
+++ b/tutorial/explainer_tutorial_1.ipynb
@@ -0,0 +1,565 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Explainer utility in BPMN2CONSTRAINTS\n",
+ "\n",
+ "In this notebook, we explore the `Explainer` class, designed to analyze and explain the conformance of traces against predefined constraints. Trace analysis is crucial in domains such as process mining, where understanding the behavior of system executions against expected models can uncover inefficiencies, deviations, or compliance issues.\n",
+ "\n",
+ "The constraints currently consists of basic regex, this is because of it's similiarities and likeness to declarative constraints used in BPMN2CONSTRAINTS\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Step 1: Setup"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "sys.path.append('../')\n",
+ "from explainer.explainer_util import Trace, EventLog\n",
+ "from explainer.explainer_regex import ExplainerRegex\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Step 2: Basic Usage\n",
+ "Let's start by creating an instance of the `Explainer` and adding a simple constraint that a valid trace should contain the sequence \"A\" followed by \"B\" and then \"C\".\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [],
+ "source": [
+ "explainer = ExplainerRegex()\n",
+ "explainer.add_constraint('A.*B.*C')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Step 3: Analyzing Trace Conformance\n",
+ "\n",
+ "Now, we'll create a trace and check if it conforms to the constraints we've defined."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Is the trace conformant? True\n"
+ ]
+ }
+ ],
+ "source": [
+ "trace = Trace(['A', 'X', 'B', 'Y', 'C'])\n",
+ "is_conformant = explainer.conformant(trace)\n",
+ "print(f\"Is the trace conformant? {is_conformant}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Step 4: Explaining Non-conformance\n",
+ "\n",
+ "If a trace is not conformant, we can use the `minimal_expl` and `counterfactual_expl` methods to understand why and how to adjust the trace.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Constraint: A.*B.*C\n",
+ "Trace:['A', 'C']\n",
+ "Non-conformance due to: Constraint (A.*B.*C) is violated by subtrace: ('A', 'C')\n",
+ "\n",
+ "Addition (Added B at position 1): A->B->C\n",
+ "-----------\n",
+ "Constraint: A.*B.*C\n",
+ "Trace:['C', 'B', 'A']\n",
+ "Non-conformance due to: Constraint (A.*B.*C) is violated by subtrace: ('C', 'B')\n",
+ "\n",
+ "Addition (Added A at position 1): C->A->B->A\n",
+ "Subtraction (Removed C from position 0): A->B->A\n",
+ "Addition (Added C at position 2): A->B->C->A\n",
+ "-----------\n",
+ "Constraint: A.*B.*C\n",
+ "Trace:['A', 'A', 'C']\n",
+ "Non-conformance due to: Constraint (A.*B.*C) is violated by subtrace: ('A', 'A')\n",
+ "\n",
+ "Addition (Added B at position 1): A->B->A->C\n",
+ "-----------\n",
+ "Constraint: A.*B.*C\n",
+ "Trace:['A', 'A', 'C', 'A', 'TEST', 'A', 'C', 'X', 'Y']\n",
+ "Non-conformance due to: Constraint (A.*B.*C) is violated by subtrace: ('A', 'A')\n",
+ "\n",
+ "Subtraction (Removed TEST from position 4): A->A->C->A->A->C->X->Y\n",
+ "Addition (Added B at position 1): A->B->A->C->A->A->C->X->Y\n",
+ "-----------\n",
+ "Constraint: AC\n",
+ "Trace:['A', 'X', 'C']\n",
+ "Non-conformance due to: Constraint (AC) is violated by subtrace: ('A', 'X')\n",
+ "\n",
+ "Subtraction (Removed X from position 1): A->C\n",
+ "-----------\n",
+ "constraint: AC\n",
+ "constraint: B.*A.*B.*C\n",
+ "constraint: A.*B.*C.*\n",
+ "constraint: A.*D.*B*\n",
+ "constraint: A[^D]*B\n",
+ "constraint: B.*[^X].*\n",
+ "Trace:['A', 'X', 'C']\n",
+ "Non-conformance due to: Constraint (AC) is violated by subtrace: ('A', 'X')\n",
+ "\n",
+ "Subtraction (Removed X from position 1): A->C\n"
+ ]
+ }
+ ],
+ "source": [
+ "non_conformant_trace = Trace(['A', 'C'])\n",
+ "print('Constraint: A.*B.*C')\n",
+ "print('Trace:' + str(non_conformant_trace.nodes))\n",
+ "print(explainer.minimal_expl(non_conformant_trace))\n",
+ "print(explainer.counterfactual_expl(non_conformant_trace))\n",
+ "\n",
+ "non_conformant_trace = Trace(['C', 'B', 'A'])\n",
+ "print('-----------')\n",
+ "print('Constraint: A.*B.*C')\n",
+ "print('Trace:' + str(non_conformant_trace.nodes))\n",
+ "print(explainer.minimal_expl(non_conformant_trace))\n",
+ "print(explainer.counterfactual_expl(non_conformant_trace))\n",
+ "\n",
+ "non_conformant_trace = Trace(['A','A','C'])\n",
+ "print('-----------')\n",
+ "print('Constraint: A.*B.*C')\n",
+ "print('Trace:' + str(non_conformant_trace.nodes))\n",
+ "print(explainer.minimal_expl(non_conformant_trace))\n",
+ "print(explainer.counterfactual_expl(non_conformant_trace))\n",
+ "\n",
+ "\n",
+ "non_conformant_trace = Trace(['A','A','C','A','TEST','A','C', 'X', 'Y']) \n",
+ "print('-----------')\n",
+ "print('Constraint: A.*B.*C')\n",
+ "print('Trace:' + str(non_conformant_trace.nodes))\n",
+ "print(explainer.minimal_expl(non_conformant_trace))\n",
+ "print(explainer.counterfactual_expl(non_conformant_trace))\n",
+ "\n",
+ "\n",
+ "explainer.remove_constraint(0)\n",
+ "explainer.add_constraint('AC')\n",
+ "non_conformant_trace = Trace(['A', 'X', 'C']) #Substraction\n",
+ "print('-----------')\n",
+ "print('Constraint: AC')\n",
+ "print('Trace:' + str(non_conformant_trace.nodes))\n",
+ "print(explainer.minimal_expl(non_conformant_trace))\n",
+ "print(explainer.counterfactual_expl(non_conformant_trace))\n",
+ "print('-----------')\n",
+ "\n",
+ "explainer.add_constraint('B.*A.*B.*C')\n",
+ "explainer.add_constraint('A.*B.*C.*')\n",
+ "explainer.add_constraint('A.*D.*B*')\n",
+ "explainer.add_constraint('A[^D]*B')\n",
+ "explainer.add_constraint('B.*[^X].*')\n",
+ "non_conformant_trace = Trace(['A', 'X', 'C']) #Substraction\n",
+ "for con in explainer.constraints:\n",
+ " print(f'constraint: {con}')\n",
+ "print('Trace:' + str(non_conformant_trace.nodes))\n",
+ "print(explainer.minimal_expl(non_conformant_trace))\n",
+ "print(explainer.counterfactual_expl(non_conformant_trace))\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Step 5: Generating minimal solutions"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Example without minimal solution\n",
+ "--------------------------------\n",
+ "\n",
+ "Subtraction (Removed A from position 2): A->B->C->B\n",
+ "Subtraction (Removed B from position 3): A->B->C\n",
+ "\n",
+ "Example with minimal solution\n",
+ "--------------------------------\n",
+ "\n",
+ "Addition (Added B at position 1): A->B->B->A->C->B\n",
+ "Subtraction (Removed B from position 5): A->B->B->A->C\n",
+ "\n",
+ "Example without minimal solution\n",
+ "--------------------------------\n",
+ "\n",
+ "Addition (Added B at position 1): C->B->B->A\n",
+ "Addition (Added B at position 1): C->B->B->B->A\n",
+ "Addition (Added A at position 1): C->A->B->B->B->A\n",
+ "Subtraction (Removed C from position 0): A->B->B->B->A\n",
+ "Addition (Added C at position 4): A->B->B->B->C->A\n",
+ "Subtraction (Removed A from position 5): A->B->B->B->C\n",
+ "\n",
+ "Example with minimal solution\n",
+ "--------------------------------\n",
+ "\n",
+ "Addition (Added A at position 1): C->A->B->A\n",
+ "Subtraction (Removed C from position 0): A->B->A\n",
+ "Addition (Added C at position 2): A->B->C->A\n",
+ "Subtraction (Removed A from position 3): A->B->C\n"
+ ]
+ }
+ ],
+ "source": [
+ "exp = ExplainerRegex()\n",
+ "exp.add_constraint(\"^A\")\n",
+ "exp.add_constraint(\"A.*B.*\")\n",
+ "exp.add_constraint(\"C$\")\n",
+ "trace = Trace(['A', 'B','A','C', 'B'])\n",
+ "print(\"Example without minimal solution\")\n",
+ "print(\"--------------------------------\")\n",
+ "print(exp.counterfactual_expl(trace))\n",
+ "\n",
+ "print(\"\\nExample with minimal solution\")\n",
+ "print(\"--------------------------------\")\n",
+ "exp.set_minimal_solution(True)\n",
+ "print(exp.counterfactual_expl(trace))\n",
+ "exp.set_minimal_solution(False)\n",
+ "trace = Trace(['C','B','A'])\n",
+ "print(\"\\nExample without minimal solution\")\n",
+ "print(\"--------------------------------\")\n",
+ "print(exp.counterfactual_expl(trace))\n",
+ "\n",
+ "print(\"\\nExample with minimal solution\")\n",
+ "print(\"--------------------------------\")\n",
+ "exp.set_minimal_solution(True)\n",
+ "print(exp.counterfactual_expl(trace))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Step 6: Contribution functions and Event Logs\n",
+ "\n",
+ "For this project, 4 contribution functions have been developed to determined a trace variant's, or constraint's contribution to a system.\n",
+ "\n",
+ "For the sake efficiency, all of the contribution functions, `variant_ctrb_to_conformance_loss`, `variant_ctrb_to_fitness`,`constraint_ctrb_to_fitness` and `constraint_ctrb_to_conformance`, should equal the total amount of conformance loss and fitness rate.\n",
+ "\n",
+ "There are to methods to determine the conformance rate (and conformance loss, by extension) and the fitness rate; `determine_conformance_rate` and `determine_fitness_rate`. \n",
+ "\n",
+ "All of these methods utilized an abstraction of an Event Log. In this block, the initialization and usage of conformance rate and fitness rate is displayed."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Conformance rate: 20.0%\n",
+ "Fitness rate: 50.0%\n"
+ ]
+ }
+ ],
+ "source": [
+ "exp = ExplainerRegex()\n",
+ "# Setup an event log\n",
+ "event_log = EventLog()\n",
+ "traces = [\n",
+ " Trace(['A', 'B','C']),\n",
+ " Trace(['A', 'B']),\n",
+ " Trace(['B']),\n",
+ " Trace(['B','C'])\n",
+ "]\n",
+ "event_log.add_trace(traces[0], 10) # The second parameter is how many variants you'd like to add, leave blank for 1\n",
+ "event_log.add_trace(traces[1], 10)\n",
+ "event_log.add_trace(traces[2], 10)\n",
+ "event_log.add_trace(traces[3], 20)\n",
+ "# Add the constraints\n",
+ "exp.add_constraint('^A')\n",
+ "exp.add_constraint('C$')\n",
+ "\n",
+ "print(\"Conformance rate: \" + str(exp.determine_conformance_rate(event_log) * 100) + \"%\")\n",
+ "print(\"Fitness rate: \" + str(exp.determine_fitness_rate(event_log) * 100) + \"%\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`variant_ctrb_to_conformance_loss` determines how much a specific variant contributes to the overall conformance loss"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Contribution of variant to conformance rate\n",
+ "Ctrb of variant ['A', 'B', 'C']: 0.0\n",
+ "Ctrb of variant ['A', 'B']: 0.2\n",
+ "Ctrb of variant ['B']: 0.2\n",
+ "Ctrb of variant ['B', 'C']: 0.4\n",
+ "Total conformance loss: 0.8\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"Contribution of variant to conformance rate\")\n",
+ "print(\"Ctrb of variant \"+ str(traces[0].nodes) +\": \"+ str(exp.variant_ctrb_to_conformance_loss(event_log, traces[0])))\n",
+ "print(\"Ctrb of variant \"+ str(traces[1].nodes) +\": \"+ str(exp.variant_ctrb_to_conformance_loss(event_log, traces[1])))\n",
+ "print(\"Ctrb of variant \"+ str(traces[2].nodes) +\": \"+ str(exp.variant_ctrb_to_conformance_loss(event_log, traces[2])))\n",
+ "print(\"Ctrb of variant \"+ str(traces[3].nodes) +\": \"+ str(exp.variant_ctrb_to_conformance_loss(event_log, traces[3])))\n",
+ "print(\"Total conformance loss: \" + str(exp.variant_ctrb_to_conformance_loss(event_log, traces[0]) + exp.variant_ctrb_to_conformance_loss(event_log, traces[1]) + exp.variant_ctrb_to_conformance_loss(event_log, traces[2]) + exp.variant_ctrb_to_conformance_loss(event_log, traces[3])))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`variant_ctrb_to_fitness` determines how much a specific variant contributes to the overall fitness rate"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Contribution of variant to fitness rate\n",
+ "Ctrb of variant ['A', 'B', 'C']: 0.0\n",
+ "Ctrb of variant ['A', 'B']: 0.1\n",
+ "Ctrb of variant ['B']: 0.2\n",
+ "Ctrb of variant ['B', 'C']: 0.2\n",
+ "Total fitness: 0.5\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"Contribution of variant to fitness rate\")\n",
+ "print(\"Ctrb of variant \" + str(traces[0].nodes) + \": \" + str(round(exp.variant_ctrb_to_fitness(event_log, traces[0]), 2)))\n",
+ "print(\"Ctrb of variant \" + str(traces[1].nodes) + \": \" + str(round(exp.variant_ctrb_to_fitness(event_log, traces[1]), 2)))\n",
+ "print(\"Ctrb of variant \" + str(traces[2].nodes) + \": \" + str(round(exp.variant_ctrb_to_fitness(event_log, traces[2]), 2)))\n",
+ "print(\"Ctrb of variant \" + str(traces[3].nodes) + \": \" + str(round(exp.variant_ctrb_to_fitness(event_log, traces[3]), 2)))\n",
+ "total_fitness = (exp.variant_ctrb_to_fitness(event_log, traces[0]) +\n",
+ " exp.variant_ctrb_to_fitness(event_log, traces[1]) +\n",
+ " exp.variant_ctrb_to_fitness(event_log, traces[2]) +\n",
+ " exp.variant_ctrb_to_fitness(event_log, traces[3]))\n",
+ "print(\"Total fitness: \" + str(round(total_fitness, 2)))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`constraint_ctrb_to_fitness` determines how much a specific constraint contributes to the overall fitness rate"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "^A ctrb to fitness rate: 0.3\n",
+ "B$ ctrb to fitness rate: 0.2\n",
+ "Total fitness loss 0.5\n"
+ ]
+ }
+ ],
+ "source": [
+ "\n",
+ "print(\"^A ctrb to fitness rate: \" + str(exp.constraint_ctrb_to_fitness(event_log, exp.constraints, 0)))\n",
+ "print(\"B$ ctrb to fitness rate: \" + str(exp.constraint_ctrb_to_fitness(event_log, exp.constraints, 1)))\n",
+ "print(\"Total fitness loss \" + str(exp.constraint_ctrb_to_fitness(event_log, exp.constraints, 0) + exp.constraint_ctrb_to_fitness(event_log, exp.constraints, 1)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Step 7: Shapely values\n",
+ "\n",
+ "`constraint_ctrb_to_conformance` determines how much a specific constraint contributes to the overall conformance loss. \n",
+ "\n",
+ "Because the constraints overlap in this case, Shapley values have been used to determine the contribution. This makes the method more complicated and more computationally heavy than the other contribution functions \n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Contriution of constraint to conformance rate\n",
+ "^A ctrb: 0.5\n",
+ "C$ ctrb: 0.30000000000000004 (adjusted 0.3)\n",
+ "Total conformance loss: 0.8\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"Contriution of constraint to conformance rate\")\n",
+ "print(\"^A ctrb: \" + str(exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 0)))\n",
+ "print(\"C$ ctrb: \" + str(exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 1)) + \" (adjusted \" + str(round(exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 1), 2)) + \")\")\n",
+ "print(\"Total conformance loss: \" + str(exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 0) + exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 1)))\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Conformance rate: 0.14\n",
+ "Contribution C$: 0.21\n",
+ "Contribution ^A: 0.36\n",
+ "Contribution B+: 0.29\n",
+ "Conformance loss : 86.0%, contribution to loss: 86.0%\n",
+ "------------------------------------\n",
+ "Fitness rate loss: 0.33333333333333337\n",
+ "C$ ctrb to fitness rate loss : 0.09523809523809523\n",
+ "^A ctrb to fitness rate loss : 0.14285714285714285\n",
+ "B+ ctrb to fitness rate loss : 0.09523809523809523\n",
+ "Total fitness rate loss : 0.3333333333333333\n"
+ ]
+ }
+ ],
+ "source": [
+ "exp = ExplainerRegex()\n",
+ "event_log = EventLog()\n",
+ "trace1 = Trace(['A', 'B', 'C'])\n",
+ "trace2 = Trace(['B', 'C'])\n",
+ "trace3 = Trace(['A', 'B'])\n",
+ "trace4 = Trace(['B'])\n",
+ "trace5 = Trace(['A', 'C'])\n",
+ "\n",
+ "\n",
+ "event_log.add_trace(trace1, 5) \n",
+ "event_log.add_trace(trace2, 10)\n",
+ "event_log.add_trace(trace3, 5)\n",
+ "event_log.add_trace(trace4, 5)\n",
+ "event_log.add_trace(trace5, 10)\n",
+ "\n",
+ "\n",
+ "exp = ExplainerRegex()\n",
+ "exp.add_constraint(\"C$\")\n",
+ "exp.add_constraint(\"^A\")\n",
+ "exp.add_constraint(\"B+\")\n",
+ "conf_rate = exp.determine_conformance_rate(event_log)\n",
+ "print(\"Conformance rate: \"+ str(round(conf_rate, 2)))\n",
+ "print(\"Contribution C$: \", round(exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 0), 2)) # Round for easier readability\n",
+ "print(\"Contribution ^A: \", round(exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 1), 2))\n",
+ "print(\"Contribution B+: \", round(exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 2), 2))\n",
+ "total_ctrb = exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 0) + exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 1) + exp.constraint_ctrb_to_conformance(event_log, exp.constraints, 2)\n",
+ "conf_rate = round(conf_rate, 2) \n",
+ "total_ctrb = round(total_ctrb, 2)\n",
+ "print(\"Conformance loss : \" + str(100 - (conf_rate * 100)) + \"%, contribution to loss: \" + str(total_ctrb * 100) + \"%\")\n",
+ "print(\"------------------------------------\")\n",
+ "print(\"Fitness rate loss: \"+ str(1 - exp.determine_fitness_rate(event_log)))\n",
+ "print(\"C$ ctrb to fitness rate loss : \" + str(exp.constraint_ctrb_to_fitness(event_log, exp.constraints, 0)))\n",
+ "print(\"^A ctrb to fitness rate loss : \" + str(exp.constraint_ctrb_to_fitness(event_log, exp.constraints, 1)))\n",
+ "print(\"B+ ctrb to fitness rate loss : \" + str(exp.constraint_ctrb_to_fitness(event_log, exp.constraints, 2)))\n",
+ "\n",
+ "print(\"Total fitness rate loss : \" + str(exp.constraint_ctrb_to_fitness(event_log, exp.constraints, 0) + exp.constraint_ctrb_to_fitness(event_log, exp.constraints, 1) + exp.constraint_ctrb_to_fitness(event_log, exp.constraints, 2)))\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".venv",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/tutorial/explainer_tutorial_2.ipynb b/tutorial/explainer_tutorial_2.ipynb
new file mode 100644
index 0000000..261b126
--- /dev/null
+++ b/tutorial/explainer_tutorial_2.ipynb
@@ -0,0 +1,681 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Explainer for Signal\n",
+ "\n",
+ "The explainer is also made for SAP Signavio Analytics Language, a query language made for performing process mining tasks on large amount of event data.\n",
+ "\n",
+ "First, import the necessary modules."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "sys.path.append('../')\n",
+ "from explainer.explainer_util import Trace\n",
+ "from explainer.explainer_signal import ExplainerSignal"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Initilize the explainer\n",
+ "\n",
+ "The signal explainer is developed to be a proof of concept, hence the code is highly tailored to be used on the selected data set. With access to more API calls and conformance queries, that do not need a data set, the explainer could be developed for a broader usage."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "exp = ExplainerSignal()\n",
+ "exp.set_endpoint('/g/api/pi-graphql/signal') #Load the data set\n",
+ "\n",
+ "# Let's add some constrainst, these are taken from the tutorial in bpmnconstraints module\n",
+ "\n",
+ "exp.add_constraint(\"(^NOT('review request'|'prepare contract')*('review request'~>'prepare contract')*NOT('review request'|'prepare contract')*$)\")\n",
+ "exp.add_constraint(\"(^NOT('prepare contract')* ('prepare contract' ANY*'send quote')* NOT('prepare contract')*$)\")\n",
+ "exp.add_constraint(\"(^NOT('assess risks')* ('assess risks' ANY*'send quote')* NOT('assess risks')*$)\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Minimal possible trace violation\n",
+ "\n",
+ "The same fashion as ExplainerRegex."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "['credit requested', 'review request', 'prepare special terms', 'assess risks', 'prepare special terms', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "---------------------\n",
+ "Non-conformance due to: Constraint ((^NOT('assess risks')* ('assess risks' ANY*'send quote')* NOT('assess risks')*$)) is violated by subtrace: ('credit requested', 'review request')\n"
+ ]
+ }
+ ],
+ "source": [
+ "trace = Trace(['credit requested', 'review request', 'prepare special terms', 'assess risks', 'prepare special terms', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent'])\n",
+ "print(trace.nodes)\n",
+ "print(\"---------------------\")\n",
+ "print(exp.minimal_expl(trace))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Counterfactuals\n",
+ "\n",
+ "Also, similar to ExplainerRegex."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Addition (Added review request at position 0): review request->credit requested->review request->prepare special terms->assess risks->prepare special terms->prepare contract->assess risks->prepare contract->send quote->send quote->quote sent\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(exp.counterfactual_expl(trace))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Contribution functions\n",
+ "\n",
+ "We'll start with conformance rate and fitness rate, given some arbritary constraints."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Conformance rate: 0.71\n",
+ "Fitness rate : 0.8933333333333333\n"
+ ]
+ }
+ ],
+ "source": [
+ "conf_rate = exp.determine_conformance_rate()\n",
+ "fit_rate = exp.determine_fitness_rate()\n",
+ "print(\"Conformance rate: \" + str(conf_rate))\n",
+ "print(\"Fitness rate : \" + str(fit_rate))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`variant_ctrb_to_conformance_loss` determines how much a specific variant contributes to the overall conformance loss.\n",
+ "\n",
+ "This is done slightly different when working with a data set, because all variations have to be considered"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Contribution is: 0.0, for trace ['review request', 'calculate terms', 'credit requested', 'calculate terms', 'assess risks', 'prepare contract', 'review request', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.0, for trace ['credit requested', 'review request', 'review request', 'prepare contract', 'assess risks', 'calculate terms', 'assess risks', 'calculate terms', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.0, for trace ['credit requested', 'calculate terms', 'review request', 'review request', 'assess risks', 'calculate terms', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.0, for trace ['credit requested', 'review request', 'review request', 'assess risks', 'assess risks', 'calculate terms', 'prepare contract', 'calculate terms', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.01, for trace ['send quote', 'credit requested', 'review request', 'calculate terms', 'assess risks', 'calculate terms', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'review request', 'quote sent']\n",
+ "Contribution is: 0.0, for trace ['credit requested', 'review request', 'review request', 'calculate terms', 'calculate terms', 'assess risks', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Total distribution to the conformance loss is 0.2900000000000001\n",
+ "Our total conformance loss is 0.29000000000000004\n"
+ ]
+ }
+ ],
+ "source": [
+ "total_contribution = 0\n",
+ "i = 0\n",
+ "for trace in exp.event_log.get_traces():\n",
+ " i +=1\n",
+ " ctrb = exp.variant_ctrb_to_conformance_loss(\n",
+ " event_log=exp.event_log,\n",
+ " trace=trace,\n",
+ " )\n",
+ " total_contribution += ctrb\n",
+ " # Let's just show some traces\n",
+ " if i % 10 == 0:\n",
+ " print(f\"Contribution is: {ctrb}, for trace {trace.nodes}\")\n",
+ "print(f\"Total distribution to the conformance loss is {total_contribution}\")\n",
+ "print(f\"Our total conformance loss is {1 - conf_rate}\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`variant_ctrb_to_fitness` determines how much a specific variant contributes to the overall fitness rate.\n",
+ "\n",
+ "This is also done in the same way"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Contribution is: 0.0, for trace ['review request', 'calculate terms', 'credit requested', 'calculate terms', 'assess risks', 'prepare contract', 'review request', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.0, for trace ['credit requested', 'review request', 'review request', 'prepare contract', 'assess risks', 'calculate terms', 'assess risks', 'calculate terms', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.0, for trace ['credit requested', 'calculate terms', 'review request', 'review request', 'assess risks', 'calculate terms', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.0, for trace ['credit requested', 'review request', 'review request', 'assess risks', 'assess risks', 'calculate terms', 'prepare contract', 'calculate terms', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.003333333333333333, for trace ['send quote', 'credit requested', 'review request', 'calculate terms', 'assess risks', 'calculate terms', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'review request', 'quote sent']\n",
+ "Contribution is: 0.0, for trace ['credit requested', 'review request', 'review request', 'calculate terms', 'calculate terms', 'assess risks', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Total distribution to the fitness is: 0.10666666666666662\n",
+ "Our total fitness rate loss is: 0.10666666666666669\n"
+ ]
+ }
+ ],
+ "source": [
+ "total_contribution = 0\n",
+ "i = 0\n",
+ "for trace in exp.event_log.get_traces():\n",
+ " i +=1\n",
+ " ctrb = exp.variant_ctrb_to_fitness(\n",
+ " event_log=exp.event_log,\n",
+ " trace=trace,\n",
+ " )\n",
+ " total_contribution += ctrb\n",
+ " # Let's just show some traces\n",
+ " if i % 10 == 0:\n",
+ " print(f\"Contribution is: {ctrb}, for trace {trace.nodes}\")\n",
+ "print(f\"Total distribution to the fitness is: {total_contribution}\")\n",
+ "print(f\"Our total fitness rate loss is: {1 - fit_rate}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`constraint_ctrb_to_fitness` determines how much a specific constraint contributes to the overall fitness rate"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Contribution is: 0.06666666666666667, for constrainst (^NOT('review request'|'prepare contract')*('review request'~>'prepare contract')*NOT('review request'|'prepare contract')*$)\n",
+ "Contribution is: 0.016666666666666666, for constrainst (^NOT('prepare contract')* ('prepare contract' ANY*'send quote')* NOT('prepare contract')*$)\n",
+ "Contribution is: 0.023333333333333334, for constrainst (^NOT('assess risks')* ('assess risks' ANY*'send quote')* NOT('assess risks')*$)\n",
+ "Our total contribution to the fitness rate is: 0.10666666666666666\n",
+ "Compared to our fitness rate loss : 0.10666666666666669\n"
+ ]
+ }
+ ],
+ "source": [
+ "ctrb_0 = exp.constraint_ctrb_to_fitness(exp.event_log, exp.constraints, 0)\n",
+ "ctrb_1 = exp.constraint_ctrb_to_fitness(exp.event_log, exp.constraints, 1)\n",
+ "ctrb_2 = exp.constraint_ctrb_to_fitness(exp.event_log, exp.constraints, 2)\n",
+ "\n",
+ "print(f\"Contribution is: {ctrb_0}, for constrainst {exp.constraints[0]}\")\n",
+ "print(f\"Contribution is: {ctrb_1}, for constrainst {exp.constraints[1]}\")\n",
+ "print(f\"Contribution is: {ctrb_2}, for constrainst {exp.constraints[2]}\")\n",
+ "\n",
+ "print(f\"Our total contribution to the fitness rate is: {ctrb_0 + ctrb_1 + ctrb_2}\")\n",
+ "print(f\"Compared to our fitness rate loss : {1 - fit_rate}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Shapley values\n",
+ "\n",
+ "`constraint_ctrb_to_conformance` determines how much a specific constraint contributes to the overall conformance loss. \n",
+ "\n",
+ "Because the constraints overlap in this case, Shapley values have been used to determine the contribution. This makes the method more complicated and more computationally heavy than the other contribution functions \n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Contribution is: 0.19, for constrainst (^NOT('review request'|'prepare contract')*('review request'~>'prepare contract')*NOT('review request'|'prepare contract')*$)\n",
+ "Contribution is: 0.040000000000000036, for constrainst (^NOT('prepare contract')* ('prepare contract' ANY*'send quote')* NOT('prepare contract')*$)\n",
+ "Contribution is: 0.06, for constrainst (^NOT('assess risks')* ('assess risks' ANY*'send quote')* NOT('assess risks')*$)\n",
+ "Our total contribution to the conformance loss is: 0.29000000000000004\n",
+ "Compared to our conformance loss : 0.29000000000000004\n"
+ ]
+ }
+ ],
+ "source": [
+ "ctrb_0 = exp.constraint_ctrb_to_conformance(exp.event_log, exp.constraints, 0)\n",
+ "ctrb_1 = exp.constraint_ctrb_to_conformance(exp.event_log, exp.constraints, 1)\n",
+ "ctrb_2 = exp.constraint_ctrb_to_conformance(exp.event_log, exp.constraints, 2)\n",
+ "\n",
+ "print(f\"Contribution is: {ctrb_0}, for constrainst {exp.constraints[0]}\")\n",
+ "print(f\"Contribution is: {ctrb_1}, for constrainst {exp.constraints[1]}\")\n",
+ "print(f\"Contribution is: {ctrb_2}, for constrainst {exp.constraints[2]}\")\n",
+ "\n",
+ "print(f\"Our total contribution to the conformance loss is: {ctrb_0 + ctrb_1 + ctrb_2}\")\n",
+ "print(f\"Compared to our conformance loss : {1 - conf_rate}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Combining BPMN2CONSTRAINTS and the Explainer\n",
+ "\n",
+ "By using code from the bpmnconstraints tutorial, one can extract the constraints from a diagram and apply the explainer to that data set"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAABCoAAAF1CAYAAAAutQtPAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58+1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAIABJREFUeNrsnQm4TVUbx9dFyJCpopQmadBcSqHQIGRqIFHK11waaU6DBkWJNJEmpcGcMWmeS4OoRCGZh5QhFO63fnuvfdu2c+89dzr33HP/v+d5n3vPPvvsYe29pv9617uMEUIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIsQ33Wbs4gedraW2Ikl0IIYQQQiSSUkoCIUQx5xJrV1s7zH1eae0Law9Z+yjJrrWttWnWnk3Q+Q611sXa//SaCCGEEEKIRFFCSSCEKMbcam2Qte+tdbTW2dpj1ipZKx/ar7q1D5VcmfKktaZKBiGEEEIIkR/Io0IIUZy51tpIa+dHtt8f+dzC2h5KrkzrkXOtTVBSCCGEEEKI/GpgCiFEcaWqtV+z2ecya7dYq2btebftK+N7EcARrqN+oPE9MZZYe9ps64FxnNunh7XLrbWyVtraImsDrH0ZOWcZa9dYO82V0zOt9ba2Ocb1HWytk7WDrFWxttz4cSWmhPY5zJ33SmvNrXWztqO1K6zNcvtwrkvdff5h7ZlMzhfmEGv3uPNeb+1st/06a3+Fru9Ga/ta22Rtoku78LGJvTHV2g/Werrjvu+O3cbd21PG94AhLbdam2ytn7Vy7vgnumMxbefB0PlhT5eex7jPTO95x9or1tYqGwghhBBCJBcllQRCiGIMwSKPtjbM2oZM9jnddXQrW3vL2p/W5lv70X3/phM8PrX2nbUG1m53HelFbp9G1h62Vt/akdbetTbX2qmuk80xlrl9mZKHd0IXJzZ8bG1vaw+4MnuBtTGh63vNWi3XQZ/m7ucOa59Ym+f2Ocp16hc5kYDYGwutTbK20dqF1oa7Y491IsKd1moY35Pk3kzS5jD3/bHWPje+6POnO/c/1k5ygs0ad80bnVhTz9oboeMMcOJDHyfgcH2znUDTwYkM7ZzQQTqnuePs7dK6jBM21jkx5gRrL7lj7+yeyy7Wxln72VoFJ6o8FYcYI4QQQgghEow8KoQQxZnuTnygQ/yItRetrYjswzSQmq7De0+MYzRyHeiAZ50IQMyLsKcEAsRaJ3wEPOHEga7G90KA9sb3bqAjPTK075Vu/48j528ROf8gJ4LgZfFOaHuaEzAQSn4PbScWx2NOSDgztP3xkBiTGVOd+HGV8cWe8PQPRJXnjO9BcXZo+3tu2xlOOAi4wYkjD8U4z67W+htfrAlAYLjciQ1Xhrb/7p5lLZe2Jxs/xgheGiv1ygshhBBCJD8KpimEKM7Q6cfb4DPjTxdAYHjZ2j45OMamyGc8M352neMoT0c+432ASLJXaFtb18EeGdmXTv8/cZz/X3fMWOd/KCJSAEEwKzmxIswik7e4E8cbf7pH9Lh4cTAto3lkO/f8cBbHezHy+Qv394VMtgcxRYL7ZXUXeREKIYQQQhQB5FEhhCjuICrgSbC768wSYLO18Ufiv4rj93SIzzH+Up61XGf4YNfxjjIvxrZ/I2VxbSc0RGHaxMIY25megRcG0zD2csc6NJNr/yLGttrub6xzzslDutZ1fxEfomIKUzWiQgrXm57JsfCeWBQj3UyM7cFUjh3cX6aK3GV8bxjijeDxQgyPJXr1hRBCCCGSEwkVQgjhs9h1ZvFcINYDUz5Oy+Y3CARDje+RQWyHD6z9ZvxAlLH4J47rKB2jYx+wMfKZGBvEemB51VHGj+2AB0GfTH6/KZPzxTq2yeI64qGM+4vXyvrId+8bXyDK6t7C/JvFd1vjuBZibLxg/KkiVxt/Ckwvs/3qLkIIIYQQIgmQUCGEENtCR5+4FY2z2Y+YD8SMIN5Cu8h3eQnQyKodu2XyXdXIZ4JQEsTyFLOtN8LGHJwvCOLJOaMroFTJw30EHguvWvs2CZ4rHi63GV+Mus8ZIsoHeuWFEEIIIZILxagQQojtYTpEOJYDI/rlI/vwmQCb0yPbWSGkTh7OTeeZlTt2j2xnic4akW1MNcGbIixScE1H5OB8n7jft4rxXZM4fh94O1SMbH/f+ILJRUn2bPESYblZxKRD9aoLIYQQQiQfEiqEEMUVxARiFZxn/JU79ja+FwXBNFlGtF9o3xnGX3mCGBYVnIjAUpiz3e8RFspZO9H4U0BW5OG6mDbCVInh7ri7uOtjVY2/IvviqcCKGse68xPAcry11Tk4H3EoRhvf06C9O9+B1gZa2y+O3//mrutyly7Enijr0qC38adaMBXlEJfGBO+8291bIuCZsKIKMTNKu3siZgWxRD5TNhBCCCGESD409UMIUVz529oxxl8aNMyPrvM/KrSNOBQE3BzkbIq1Zta6GH9qwzS3H53zbsb3aNgnl9fFlAmWMH0udNxV1nqY7T0cLrY2wvwXJPMPtx+iykk5OCf3Mdj4YggdeLwNXje+N8SIbH77rxMjWNEkCGyJ0EEMinuciIEHQ/fQb34wvhCTCDa7NAkLT8QjudDa18oGQgghhBDJR5qSQAhRzMFDYmf3/1onCmQG3gI7OjEhHGhyL1eeEgdhaz5eW03jr16xyGQdUHJPJzAsNHmLj1HZ2Z/OcsKOLn3wNFkZ4/sgjdYYX1BJNMTgKOPSZ6FeeyGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQhRTHjJ+UMwAVnXav4DOta+1560dEMe+e7l9D9YjEkIIIYQQ8aBVP4QQIjVgVZJK1l50n8+39oLxly79Kp/PxRKmF7rj/5zNvtXcviz7+mMOztHa2hXGX3KV+yLQ6Thr15rYwTqFEEIIIUSKIKFCCCFSE5beHGltXhG9/sbGX3nkRmvzje+RcZfxl009WY9XCCGEECJ1kVAhMkhPTy85cODAq7/++uuLpk+ffsCyZctKL168uIRSJm/UqFFjc6VKlf6qWbPmR/PmzXvQ2pdKFZEAZlo7u6CLjQI89g2Rz+9Y+8faU8ZfTnalyjOVZ0JtDqE8qnykfKR8JKFCpDAvvvhil+bNmw+YOXPmThdccIG55JJLTK1atcwee+yhxMkjCxcuLLVgwYJqEyZMaPvTTz+1qlOnzrezZ88+1371q1InpahgraO1htZqWdtk7QNr/axtDO33mLVh1kpau4b60No6ay9ZGx45Zl/je0VssXadtd3cvq9Yey2b6znKWjdrN1tbHtq+u9t+nLU0a4uNH0Niqvt+P+NPG6nrBIHVxp9OMjbGObZa6+oEkR2t/WLtUWs/xZFeVaxdb62R+8z0lD7WVmTxmyXumsuqPFN5JtTmEMqjykfKR8pHqUuakkD07dv3hYcffrhL9+7dzTXXXGPKlCmjRCkgNm3aZAYMGGB69eq1wX5sv3bt2vFKlZQBkaK3tTGuo36g8WMsjLDWKbQfwsAMa4c4wWKVtQbWzrDW01qv0L7zrc0x/rSHV43vRVDfWhu3X8/QvuyH18Hl7nNba6ONH1DzF7eN47zvhJPX3d961oaERBK272ntXepqay3dtbUP7YPI8bm1z6yVNn7sCMSUs9z5mpj/4mIgmDAN5RR3fUCMi0+N75HxfEjw4FjHZiJWpLn72cfa4SrPVJ4JtTmE8qjykfKR8lHqUlJJULzp3bv3kH79+l00ZswY06FDB1OqlJxsChLSt0GDBqZJkyY7DBs2rO3GjRu/DXUiRdFmlrX+1iZam2ZtsvFH/i+19rDryAMxFw5wAsEb1j52IgSeDnhNvGBtjduXz3WdMPCa2/c119HHG2Go8eM4AN4ZxKMIKlCEEtT/x6394baNcGLAUU5ceM9sH+SS7YOcUDHNnQ8Bopa7TmC45mInupzgjvOhu3b2PdWJH4AXyGXG9xgJ4mX0d2nAdeDJ8Yk7z03WKlubFM061p611sL43huLVZ6pPBNqcwjlUeUj5SPlo9RFc5iKMYMHD+5oC7quo0aNMvXr11eCJBDSe9KkSeUsdM72U4qkBJtDYkTAd9Z2sFY1sh0RYG5kWx/XIW8Z2Y4AMCfGvgjNZ+Tg+hBCTnTCxZ9Z7Lcp8hmvh+nWdo2x70vuvsO/fc74Xh/VMzl+SSegPB+5DrxF8LhoHuM3L7t0CXtqqDxTeSbU5hDKo8pHQvlIQoVIJdLT09OGDx/+5I033qiCrhALvNtuu61E6dKlH1VqpASIDO2MH4NilPG9DO7KpKydH+P3qPMbYlR+sVbt+M34Xhc5qSgPdH+nZ7MfcSmYsoJXxWR3HydnUl/EGlGY5f7WzuT4exk/nkd7d+ywnRBD4GgVEim+UXmm8kyozSGUR5WPlI+UjyRUiBSld+/e/5s1a1Zl5rWJwqN79+4VypQpQ/DFw5UaRZpK1r6w9ozx4y28afwgmmMy2X9rJtv/NdsHOc5q3x1ycI3BBNZNWezT0IkPlxhfIGGqx/0h8SHK5iy2lcrmOn4wfryMsJF+vSP7H2/86Sg/qjxTeSbU5hDKo8pHykfKRxIqRAozY8aMS8477zwF3ylkSP8OHTr8Zfx5/aLocpW1I4wfFJNlNV9wYsW8TPaPNS2C6SEVrS2LY1/2Y9WMpTm4xmDfPbPYhxECpqQQP+NB46/2QQyJtTm4j5ru77IsroPpJCz1dU8MeyCyP1NfXlJ5pvJMqM0hlEeVj5SPlI8kVIjUL+wOatmypRIiCejUqRMd1FOVEkUapjOsN9vHkjglk/1PMv95FgScY/yVLT6MbGf5zh1j7Fsixr5ZMdP4q2m0z2KfWm6/cKyN8sb3aojFaTG2tTb+MqKzM/nNaidSdDbxeYR8ZPxgmyrPVJ4JtTmE8qjykVA+klAhUpnly5eX23fffZUQSUCdOnV2SktL20spUaQhdgJeDqzEwaoVext/ysSJmexfzvhLkx5m/CCVrGTByiDvG3/ZzjAIGgRuOtztSxyMR4y/AkhOhAqmitznzsXvDzJ+HAmO18ztQyTrFu66uUY8K8aazKeLED+ih7tfgnXeZvwRhodM5lNW4CZ3fqZ0NHC/Z1lSYmNcENmXa5rnrkflmcozoTaHUB5VPhLKR8UArWdTTFm5cmXJ6tWrKyGSAPsc0tLT03dVShRpWOniBCcAPOo66SNch//XGPsPNP5Ujy+dEMFUCKaKdI2x79PG92r4wvznhTHO7Zuew+sc4P7eYfwpKvCPtW7uf/6OtPaB+8yUj57WXjd+3Iowa5zIwDKkD7tt693+/bO5DgSWZi6tPg5tZ7pI98i+Fd39l1J5pvJMqM0hlEeVj4TykYQKkcJs2bLFlCxZUgmRBLjnoIdRtMFboYu164wfWJO5i6vdd2kx9kdwuNz43gjVXKf/j0yOXdb4MTBuNv6KHIgHq2Lst3/k85hMzo1YwRKlwUjAcmt/u/8JpInnBnEmmJbBFI7Am2Jw6BhfuPsEAkrRcmJ6CvEnNkbO900m18ESrcT1oKIv59JwUYz9jrNW2qWRyjOVZ0JtDqE8qnwklI8kVAghhMgBq0MCRVYEHfe1JvNAldF91znLD/DEmJ/F94tyeLxlebiW5dl8v0CvlRBCCCFE8UIxKoQQQgghhBBCCJE0SKgQQgghhBBCCCFE0qCpH0IIkViIYzEvzn0JLPm7kkwIIYQQQhQnJFQIIURieSMH+45QcgkhhBBCiOKGpn4IIYQQQgghhBAiaZBQIYQQQgghhBBCiKRBQoUQIreUUxIoDYQQKhuEUB4VQuQ3EiqEEDnm2GOPbVu5cuXVrVu37qQ0KL5pIIRQ2SCE8qgQoiCQUCGEyHEF/8svvwy//fbbS3/yyScvnnLKKe2VBsUvDYQQKhuEUB4VQhQUEiqEEDmu4EeNGlWqe/fuZuTIkSW//fbbYQ0aNDhTaVB80kAIobJBCOVRIURBIqFCpAR///23+f3335UQCargTzrpJG8bf6nof/rpp9cPO+ywVkqD1E8DkTn2HTAXXXSRmT9/foEcf9WqVd7xv/zySyW2ygYhhPJosea6664zr732mhIihSmlJBD5yT333GNeeOGFjM/lypUz++yzjzn55JPN5ZdfbnbccccCOe8VV1xhxowZY/766y89hARV8AF8ZvuZZ545qk6dOm1mz549UWmQkDS439of1h6J8d3/rB1prZu1dFfWX2KtjbWdrM2z1s/atNBv0qx1sXaWtV2sbbD2rTVaASnbM165cqXp06ePGTt2rPn555+9bVWqVDH16tUzjLideuqpcR9r6dKlXvl39dVXm7333jvfr3XdunXe8Zs3b877qIJJZUOxo3///uaxxx7L+FypUiUvr51++umma9eupnTp0kokoTxaAEyaNMncf//9nlD+77//mp122skceeSRXtv+3HPPLZRrev31103JkiUL7fxCQkWB8PLLL5/xxRdfXDl9+vR6f/75ZwXbUC29ePHiEjVq1NhctWrVDbYzvbJatWpj58yZ89i8efN+02sSP3/88YdZvny5uemmmzK2ff/9997noUOHms8++8yUKVMm389LI6VixYp6AAmu4KMVfbt27cbsueeerX7//fe3lAYFngZbrN1n7Tlrq0PbS1rrZe1tJ1IgQLxuram1p6z95gSLT6y1tDY1JHxca+1Za+Os7cltWZuTqkLF119/bVq0aGHWr1/veSrcdtttXkfn119/9YSL9PT0lLlXGpZHHXWUmTFjhgo1lY9FFttmM7/99pu56667MrbZ9py58sorzfPPP28++OADU7ZsWSWUUB7NR8aPH2/atGljmjRpYp5++mmvvb1o0SIzZcoUT6AXhU5Na3gEtbBWw9pu1vawttDaEms8pImubbdIQkUSYhucOzzyyCN9RowYccW1115b+owzzjDdunXzlPgaNWqYPfbYwyxcuLCUzXAV58+fX9FmyuumTZt27X777fe7/e2Vc+fOnaB8EB94TYQbEfDGG2+YDh06mFdffdVceOGF+X7Ojh07eiYSX8GHK/rRo0fv0LZt2zerVavWctWqVVOVBgWaBggKt/H6W3sytP1kV0k97z53sNbW2gm06d22QdamWBto7cAgG7nj9CgO7zbeV61bt/bKq08//dTYsn6b72+//faUut8PP/zQm5oiVD4WddLS0rZrYzAQcsEFF5gXX3zRXHbZZUokoTyajzz++OOmTp06njBRosR/UQOYeiEKlSbW7rHWKJPv93BmnJDBYNVH1ihA35NQkSS89NJLFzZt2vSJhQsXlrvvvvvMWWed5bkKbfc099jDs2OOOcacffbZZsuWLWkjR46sdeutt47dZ599fpw3b147u9uvyhc558wzz/QKt5kzZ26znTnXjz76qNdRgOOOO8706NHD2ErCGwFklOSUU07xRI4oTDNh9NM+H7xkzHfffWf69u27zT54cDzxxBOe8ss0lPbt23uNGRo6zCPnGLhpH3300Rm/4VoGDx5sOnfu7E1ZCeDaH3nkEa8DU7t2bVXwmVT0Y8aMKd2mTZvxFSpUaLFu3bp3lQYFlgYLrDHq0zUiVHQ2/tSOD9xnll/7PCRSAK4CI6w9bW0ftz+eFi3dtpQv52h4LV682LzzzjvbiRSxYFoI5cyPP/7oeY7tvPPOnqs50zCyY8WKFWbAgAFe2bJ161az6667mvPPP98gmCMePPzww+bOO+80++677za/e+qppzwPtWinLMrkyZPNuHHjzNy5c83GjRvNwQcfbG644YaM+xoxYoS5++67vXPjOQKci3MG2Aa618lDwOHe6OxR9gqVj0WBTp06mauuuspMmzYtQ6i4/vrrvQGMmjVrmnvvvdfMnj3by3M33nij9z2eVORLygDb3jOHHHKI1/6oVatWxnEnTJhgpk+f7g1s0b5A8IP69et7U8Noq4Qhjw8fPtzYd8ObqsVg2DXXXOO5yAe89dZbnvs8+W/IkCHeHPvNmzebiRMnZkyPfffdd80zzzzj5X9G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GqQaeX2vhyXqQidPnuzZY489pgIx7+VZUtWLyVo22MZrUq36URzbHKeccop54YUX8hxQN7ewtOMxxxyz3RLqRTmPplIbJgd5NNftl0TXdckAq+6wAtWFF15YVOu6vJabrPpxDBu//vrrAg2oyfFD/J4saZxSQoXNxCMnTpxYN5HLkz777LO8hG8X0v16BZt74dPiWZZRTejcM2vWLPPJJ59ss450YZNdxR7ruf/+++9vVatWrWWbNm3Gjx07tkxhVPTRDnqeWj1xiBP5kQY9evTIWKIOgojsqNDr1q3ztm3cuNHccMMNZsiQIQlNg1QjN+91okCoDJ63SMp2QJ7qRZUNanNEmT9/vhe0OOotk0iGDRtmDjroIJX1KdaGyU37pTjx2muvma5duxbnOon+pbc86ZgxYwp0eVKOHzmvhIr8Zvr06YMWLFhwu30RSqJcFTT2PH///PPPh9l/zy+M+02WAo6GFxnx/PPPN3369DFvv/22t9woBUy4sHnllVe8RhvfMfp04oknRtPTPPfcc2bUqFFeo46lZm+55RYzZ84c8/3335ubb77Z22/GjBnm0Ucf9SIxR5cKe+KJJwiq6s0J3ibH2WsaPHiwWbFiBXO/zEUXXWTatm27zT4fffSRtw/rNMP+++9vbJp6+02ZMiXDjfC6667zlvHD7euRRx4plHc9r8991apVUytUqNCidevWE958882yiazo86uCT2QafP755947vHZtRgBmU65cOa/xeuSRR2Z0RjZs2OC5eF9yySWmfv36EikS/EwLEp4x5RvvAUGnKEPg3HPPJVZRxj4DBgww7777rlee4TJOJza8pNr48ePNzJkzvbKNVSKGDx/uNdYpY+w76W3v16+ftx9lJmVh7dq1ze233+51fpliwLzYv//+24vSTeeXkdYAOlMcd9KkSd5IftmyZb1RmE6dOqVkR6cg6kWVDcnb5pg9e7YZOHCg1w6AffbZx/NWqVevXsY18jywNWvWeEvD4oVwwQUXeK7W4XxIIDzq8/79+3vPi3xIXiPP1qnje2yTl4O6n+32vfDs8ccf9zxp+D2jvohSDzzwgNfGIE8S9BHxasSIEea9994zv/76q3eM4447znTv3n27ZRuXLl3qlR28T9xDMIq87777ml69epnffvvNa59wPXD//fcX6dgZxb0NU1TECYT5559/3ivfeN+u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F8yVV14poUIIIYQQSYuECiGEEIXKTTfddFjjxo33bNGiRR37sUt6evov9u8nphiJFjmlffv2pnr16koIIYQQQqQkEiqEEEIUKn369DnYmqlYseLm5s2bL+7SpUuVFi1a1DYSLTLl3nvvVSIIIYQQImWRUCGEECIpWLt2bak33nijFpYsosXHH39sBg8ebBYsWOB9rl27trHXY9q1a+d9njhxovn222/Ntddea/r27Ws++OADb/txxx1nevTosd3SpP/++695+umnzYQJE8ymTZu86Rfsd9BBB22z39atW82wYcPM8OHDzZo1a0y5cuXM0Ucfbe666y5TsmRJT6jYeeedvSkcAbNnzzYvv/yy+eGHH8wff/zhnbtr167e9QohhBBCSKgQQgghEidaFMg1TJkyJUOUaNOmjScYTJs2zYwYMSJDqJg5c6bp37+/GTt2rBczolmzZmblypVm0KBBZuTIkebLL780VapUyRAfWrVqZb766itz6aWXmt12283bp169euadd97xxA2w92Y6duxoRo0aZc466yxz1FFHmYULF5qffvrJEylg/PjxnsgRFipuvPFG89dff5kmTZqYGjVqeNdEwE725a8QQgghhIQKIYQoRtjO5TilQu7ITmgIixaVK1dOb9++/cbOnTuf0KhRo47GD8JZILz22mvmiCOO8LwasmLFihXmoosu8lbTCDj//PM9AYJtvXv39rY9++yz5t133zVff/11RhDNq666ytSvX99cd9115rPPPvO2cT57r975O3ToEPf1IqCUKVMm4/Nll11mDjjgADN06NCEChX/b+9OwGs+0/+P30cSEUVsY40wSkaNMh2qhFTQRku1ttqi9upM+0c7xNpSE1Nqi6SWoqYyat9rKzPGhSmpdiwNqkZRKrFTIY1EnN/3firnnxBbYvme5P26ruc62zffnDwni/NxP/ejIcvcuXP5eQAAAAQVAPAoWG8ui1lvNgOYiYfjwoULjunTp/voyJcvn7NKlSoFHtTn8vf3N6HBxo0bTZXC7fTs2TPD7Ro1akhISIipakgLKubMmSPPPfdchp0+tEKiTZs2MnjwYLNco2jRoiagCAgIuKeQQqUPKVSePHmkevXqZivTh0W/hn379klu/pnQ3wn8pAIAkD0EFQBw71KsN4XX9MrOnTuL6WBKHr6kpCTHrl27HntQ5+/fv7+p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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import sys\n",
+ "sys.path.append(\"../../\")\n",
+ "\n",
+ "from bpmnconstraints.script import compile_bpmn_diagram\n",
+ "import SignavioAuthenticator\n",
+ "import requests\n",
+ "from IPython.display import Image, display\n",
+ "import json\n",
+ "import logging\n",
+ "from conf import *\n",
+ "logging.getLogger(\"urllib3\").setLevel(logging.WARNING)\n",
+ "\n",
+ "system_instance = 'https://editor.signavio.com'\n",
+ "workspace_id = workspace_id# workspace id\n",
+ "user_name = user_name# username\n",
+ "pw = pw # pw\n",
+ "revision_id = '1fe7397c17304d3ba4ea41f1eefc97fe'\n",
+ "authenticator = SignavioAuthenticator.SignavioAuthenticator(system_instance, workspace_id, user_name, pw)\n",
+ "auth_data = authenticator.authenticate()\n",
+ "cookies = {'JSESSIONID': auth_data['jsesssion_ID'], 'LBROUTEID': auth_data['lb_route_ID']}\n",
+ "headers = {'Accept': 'application/json', 'x-signavio-id': auth_data['auth_token']}\n",
+ "diagram_url = system_instance + '/p/revision'\n",
+ "\n",
+ "json_request = requests.get(\n",
+ " f'{diagram_url}/{revision_id}/json',\n",
+ " cookies=cookies,\n",
+ " headers=headers)\n",
+ "json_diagram = json_request.content\n",
+ "path = './diagram.json'\n",
+ "with open(path, 'w') as f:\n",
+ " json.dump(json.loads(json_diagram), f)\n",
+ "png_request = requests.get(\n",
+ " f'{diagram_url}/{revision_id}/png',\n",
+ " cookies=cookies,\n",
+ " headers=headers)\n",
+ "display(Image(png_request.content))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "These are the constraints generated from the diagram"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "INFO:root:Generating SIGNAL constraints...\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 119/119 [00:00, ?it/s]"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[\"(^NOT('calculate terms')* ('calculate terms' ANY*'prepare contract')* NOT('calculate terms')*$)\", \"( ^ NOT('prepare special terms'|'send quote')* ('prepare special terms'NOT('prepare special terms'|'send quote')*'send quote'NOT('prepare special terms'|'send quote')*)*NOT('prepare special terms'|'send quote')* $)\", \"(^NOT('assess risks')*('review request' NOT('assess risks')*'assess risks'NOT('assess risks')*)*NOT('assess risks')*$)\", \"(^ (NOT 'review request' | ('review request' (NOT 'review request')* 'prepare special terms'))*$)\", \"(^NOT('review request'|'prepare contract')*(('review request'ANY*'prepare contract'ANY*)|('prepare contract'ANY* 'review request' ANY*))* NOT('review request'|'prepare contract')*$)\", \"(^NOT('calculate terms'|'send quote')*('calculate terms'~>'send quote')*NOT('calculate terms'|'send quote')*$)\", \"(^NOT('calculate terms'|'prepare contract')*(('calculate terms'ANY*'prepare contract'ANY*)|('prepare contract'ANY* 'calculate terms' ANY*))* NOT('calculate terms'|'prepare contract')*$)\", \"(^NOT('prepare special terms'|'calculate terms')*(('prepare special terms'ANY*'calculate terms'ANY*)|('calculate terms'ANY* 'prepare special terms' ANY*))* NOT('prepare special terms'|'calculate terms')*$)\", \"(^NOT('assess risks'|'prepare special terms')*(('assess risks'ANY*'prepare special terms'ANY*)|('prepare special terms'ANY* 'assess risks' ANY*))* NOT('assess risks'|'prepare special terms')*$)\", \"(^NOT('prepare contract')* ('prepare contract' ANY*'send quote')* NOT('prepare contract')*$)\", \"(^NOT('prepare special terms'|'send quote')*(('prepare special terms'ANY*'send quote'ANY*)|('send quote'ANY* 'prepare special terms' ANY*))* NOT('prepare special terms'|'send quote')*$)\", \"(^NOT('standard terms applicable'|'calculate terms')*(('standard terms applicable'ANY*'calculate terms'ANY*)|('calculate terms'ANY* 'standard terms applicable' ANY*))* NOT('standard terms applicable'|'calculate terms')*$)\", \"(^NOT('prepare special terms')* ('prepare special terms' ANY*'prepare contract')* NOT('prepare special terms')*$)\", \"( ^ NOT('review request'|'send quote')* ('review request'NOT('review request'|'send quote')*'send quote'NOT('review request'|'send quote')*)*NOT('review request'|'send quote')* $)\", \"(^NOT('prepare contract')*('prepare contract'NOT('prepare contract')*'send quote'NOT('prepare contract')*)*NOT('prepare contract')*$)\", \"(('review request'|'send quote'))\", \"(('prepare special terms'|'calculate terms'))\", \"(^NOT('calculate terms')*('calculate terms'NOT('calculate terms')*'prepare contract'NOT('calculate terms')*)*NOT('calculate terms')*$)\", \"(^ (NOT 'review request' | ('review request' (NOT 'review request')* 'assess risks'))*$)\", \"( ^ NOT('review request'|'prepare contract')* ('review request'NOT('review request'|'prepare contract')*'prepare contract'NOT('review request'|'prepare contract')*)*NOT('review request'|'prepare contract')* $)\", \"(^NOT('standard terms applicable'|'assess risks')*(('standard terms applicable'ANY*'assess risks'ANY*)|('assess risks'ANY* 'standard terms applicable' ANY*))* NOT('standard terms applicable'|'assess risks')*$)\", \"(^NOT('prepare contract'|'send quote')*(('prepare contract'ANY*'send quote'ANY*)|('send quote'ANY* 'prepare contract' ANY*))* NOT('prepare contract'|'send quote')*$)\", \"(^NOT('calculate terms')*('review request' NOT('calculate terms')*'calculate terms'NOT('calculate terms')*)*NOT('calculate terms')*$)\", \"(^NOT('assess risks'|'calculate terms')*(('assess risks'ANY*'calculate terms'ANY*)|('calculate terms'ANY* 'assess risks' ANY*))* NOT('assess risks'|'calculate terms')*$)\", \"(^NOT('prepare special terms')*('prepare special terms'NOT('prepare special terms')*'prepare contract'NOT('prepare special terms')*)*NOT('prepare special terms')*$)\", \"( ^ NOT('calculate terms'|'prepare contract')* ('calculate terms'NOT('calculate terms'|'prepare contract')*'prepare contract'NOT('calculate terms'|'prepare contract')*)*NOT('calculate terms'|'prepare contract')* $)\", \"(^NOT('calculate terms'|'send quote')*(('calculate terms'ANY*'send quote'ANY*)|('send quote'ANY* 'calculate terms' ANY*))* NOT('calculate terms'|'send quote')*$)\", \"(^NOT('prepare special terms'|'prepare contract')*('prepare special terms'~>'prepare contract')*NOT('prepare special terms'|'prepare contract')*$)\", \"( ^ NOT('prepare special terms'|'prepare contract')* ('prepare special terms'NOT('prepare special terms'|'prepare contract')*'prepare contract'NOT('prepare special terms'|'prepare contract')*)*NOT('prepare special terms'|'prepare contract')* $)\", \"(^NOT('prepare special terms'|'send quote')*('prepare special terms'~>'send quote')*NOT('prepare special terms'|'send quote')*$)\", \"(^NOT('prepare special terms'|'prepare contract')*(('prepare special terms'ANY*'prepare contract'ANY*)|('prepare contract'ANY* 'prepare special terms' ANY*))* NOT('prepare special terms'|'prepare contract')*$)\", \"(('review request'|'prepare contract'))\", \"(^NOT('review request'|'prepare contract')*('review request'~>'prepare contract')*NOT('review request'|'prepare contract')*$)\", \"(^'review request')\", \"(^NOT('assess risks'|'send quote')*(('assess risks'ANY*'send quote'ANY*)|('send quote'ANY* 'assess risks' ANY*))* NOT('assess risks'|'send quote')*$)\", \"(^NOT('assess risks')* ('assess risks' ANY*'send quote')* NOT('assess risks')*$)\", \"( ^ NOT('prepare contract'|'send quote')* ('prepare contract'NOT('prepare contract'|'send quote')*'send quote'NOT('prepare contract'|'send quote')*)*NOT('prepare contract'|'send quote')* $)\", \"( ^ NOT('calculate terms'|'send quote')* ('calculate terms'NOT('calculate terms'|'send quote')*'send quote'NOT('calculate terms'|'send quote')*)*NOT('calculate terms'|'send quote')* $)\", \"(^NOT('calculate terms'|'prepare contract')*('calculate terms'~>'prepare contract')*NOT('calculate terms'|'prepare contract')*$)\", \"('send quote'$)\", \"(^ (NOT 'review request' | ('review request' (NOT 'review request')* 'calculate terms'))*$)\", \"(^NOT('assess risks')*('assess risks'NOT('assess risks')*'send quote'NOT('assess risks')*)*NOT('assess risks')*$)\", \"(^NOT('review request'|'send quote')*('review request'~>'send quote')*NOT('review request'|'send quote')*$)\", \"(^(((NOT('prepare special terms')*) ('calculate terms' NOT('prepare special terms')*)*)|((NOT('calculate terms')*)('prepare special terms' NOT('calculate terms')*)*))$)\", \"(^NOT('assess risks'|'send quote')*('assess risks'~>'send quote')*NOT('assess risks'|'send quote')*$)\", \"(^NOT('prepare special terms')*('review request' NOT('prepare special terms')*'prepare special terms'NOT('prepare special terms')*)*NOT('prepare special terms')*$)\", \"(^NOT('standard terms applicable'|'prepare special terms')*(('standard terms applicable'ANY*'prepare special terms'ANY*)|('prepare special terms'ANY* 'standard terms applicable' ANY*))* NOT('standard terms applicable'|'prepare special terms')*$)\", \"(^NOT('prepare contract'|'send quote')*('prepare contract'~>'send quote')*NOT('prepare contract'|'send quote')*$)\", \"(^NOT('review request'|'send quote')*(('review request'ANY*'send quote'ANY*)|('send quote'ANY* 'review request' ANY*))* NOT('review request'|'send quote')*$)\", \"(('prepare contract'|'send quote'))\", \"( ^ NOT('assess risks'|'send quote')* ('assess risks'NOT('assess risks'|'send quote')*'send quote'NOT('assess risks'|'send quote')*)*NOT('assess risks'|'send quote')* $)\"]\n",
+ "The amount of constraints: 51\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "signal_constraints = compile_bpmn_diagram(path, \"SIGNAL\", False)\n",
+ "signal_constraints = list(set(signal_constraints))\n",
+ "print(signal_constraints)\n",
+ "print(\"The amount of constraints: \" + str(len(signal_constraints)))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now we can use the explainer with the data set and the constraints\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Conformance rate: 0.0\n",
+ "Fitness rate : 0.4780392156862745\n"
+ ]
+ }
+ ],
+ "source": [
+ "exp = ExplainerSignal() #Reset the explainer\n",
+ "exp.set_endpoint('/g/api/pi-graphql/signal')\n",
+ "for con in signal_constraints:\n",
+ " exp.add_constraint(con)\n",
+ " \n",
+ "conf_rate = exp.determine_conformance_rate()\n",
+ "fit_rate = exp.determine_fitness_rate()\n",
+ "print(\"Conformance rate: \" + str(conf_rate))\n",
+ "print(\"Fitness rate : \" + str(fit_rate))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`variant_ctrb_to_conformance_loss`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Contribution is: 0.01, for trace ['review request', 'calculate terms', 'credit requested', 'calculate terms', 'assess risks', 'prepare contract', 'review request', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.01, for trace ['credit requested', 'review request', 'review request', 'prepare contract', 'assess risks', 'calculate terms', 'assess risks', 'calculate terms', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.02, for trace ['credit requested', 'calculate terms', 'review request', 'review request', 'assess risks', 'calculate terms', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.01, for trace ['credit requested', 'review request', 'review request', 'assess risks', 'assess risks', 'calculate terms', 'prepare contract', 'calculate terms', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.01, for trace ['send quote', 'credit requested', 'review request', 'calculate terms', 'assess risks', 'calculate terms', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'review request', 'quote sent']\n",
+ "Contribution is: 0.01, for trace ['credit requested', 'review request', 'review request', 'calculate terms', 'calculate terms', 'assess risks', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Total distribution to the conformance loss is 1.0000000000000004\n",
+ "Our total conformance loss is 1.0\n"
+ ]
+ }
+ ],
+ "source": [
+ "total_contribution = 0\n",
+ "i = 0\n",
+ "for trace in exp.event_log.get_traces():\n",
+ " i +=1\n",
+ " ctrb = exp.variant_ctrb_to_conformance_loss(\n",
+ " event_log=exp.event_log,\n",
+ " trace=trace,\n",
+ " )\n",
+ " total_contribution += ctrb\n",
+ " # Let's just show some traces\n",
+ " if i % 10 == 0:\n",
+ " print(f\"Contribution is: {ctrb}, for trace {trace.nodes}\")\n",
+ "print(f\"Total distribution to the conformance loss is {total_contribution}\")\n",
+ "print(f\"Our total conformance loss is {1 - conf_rate}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`variant_ctrb_to_fitness`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Contribution is: 0.004313725490196079, for trace ['review request', 'calculate terms', 'credit requested', 'calculate terms', 'assess risks', 'prepare contract', 'review request', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.005294117647058823, for trace ['credit requested', 'review request', 'review request', 'prepare contract', 'assess risks', 'calculate terms', 'assess risks', 'calculate terms', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.010196078431372548, for trace ['credit requested', 'calculate terms', 'review request', 'review request', 'assess risks', 'calculate terms', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.004705882352941176, for trace ['credit requested', 'review request', 'review request', 'assess risks', 'assess risks', 'calculate terms', 'prepare contract', 'calculate terms', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Contribution is: 0.006078431372549019, for trace ['send quote', 'credit requested', 'review request', 'calculate terms', 'assess risks', 'calculate terms', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'review request', 'quote sent']\n",
+ "Contribution is: 0.005098039215686274, for trace ['credit requested', 'review request', 'review request', 'calculate terms', 'calculate terms', 'assess risks', 'prepare contract', 'assess risks', 'prepare contract', 'send quote', 'send quote', 'quote sent']\n",
+ "Total distribution to the fitness is 0.5219607843137256\n",
+ "Our total fitness rate loss is 0.5219607843137255\n"
+ ]
+ }
+ ],
+ "source": [
+ "total_contribution = 0\n",
+ "i = 0\n",
+ "for trace in exp.event_log.get_traces():\n",
+ " i +=1\n",
+ " ctrb = exp.variant_ctrb_to_fitness(\n",
+ " event_log=exp.event_log,\n",
+ " trace=trace,\n",
+ " )\n",
+ " total_contribution += ctrb\n",
+ " # Let's just show some traces\n",
+ " if i % 10 == 0:\n",
+ " print(f\"Contribution is: {ctrb}, for trace {trace.nodes}\")\n",
+ "print(f\"Total distribution to the fitness is {total_contribution}\")\n",
+ "print(f\"Our total fitness rate loss is {1 - fit_rate}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`constraint_ctrb_to_fitness`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Contribution is: 0.000980392156862745, for constraint (^NOT('prepare contract')* ('prepare contract' ANY*'send quote')* NOT('prepare contract')*$)\n",
+ "Contribution is: 0.019215686274509803, for constraint ( ^ NOT('review request'|'prepare contract')* ('review request'NOT('review request'|'prepare contract')*'prepare contract'NOT('review request'|'prepare contract')*)*NOT('review request'|'prepare contract')* $)\n",
+ "Contribution is: 0.01588235294117647, for constraint (^NOT('prepare special terms'|'send quote')*('prepare special terms'~>'send quote')*NOT('prepare special terms'|'send quote')*$)\n",
+ "Contribution is: 0.019019607843137255, for constraint ('send quote'$)\n",
+ "Contribution is: 0.0, for constraint (('prepare contract'|'send quote'))\n",
+ "Total distribution to the fitness is 0.5219607843137255\n",
+ "Our total fitness rate loss is 0.5219607843137255\n"
+ ]
+ }
+ ],
+ "source": [
+ "total_contribution = 0\n",
+ "i = 0\n",
+ "for con in signal_constraints:\n",
+ " ctrb = exp.constraint_ctrb_to_fitness(\n",
+ " log=exp.event_log,\n",
+ " constraints=exp.constraints,\n",
+ " index=i\n",
+ " )\n",
+ " i +=1\n",
+ " total_contribution += ctrb\n",
+ " # Let's just show some traces\n",
+ " if i % 10 == 0:\n",
+ " print(f\"Contribution is: {ctrb}, for constraint {con}\")\n",
+ " \n",
+ "print(f\"Total distribution to the fitness is {total_contribution}\")\n",
+ "print(f\"Our total fitness rate loss is {1 - fit_rate}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`constraint_ctrb_to_conformance`\n",
+ "\n",
+ "This does not seem to work currently, my suspicion is that the amount of constraints crashes the computer when applying the computationally heavy Shapley values to it "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "metadata": {}
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'\\ntotal_contribution = 0\\ni = 0\\nfor con in signal_constraints:\\n ctrb = exp.constraint_ctrb_to_conformance(\\n log=exp.event_log,\\n constraints=exp.constraints,\\n index=i\\n )\\n i +=1\\n total_contribution += ctrb\\n # Let\\'s just show some traces\\n if i % 10 == 0:\\n print(f\"Contribution is: {ctrb}, for constraint {con}\")\\n \\nprint(f\"Total distribution to the conformance loss is {total_contribution}\")\\nprint(f\"Our total conformance loss is { 1 - conf_rate}\")\\n'"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "\n",
+ "\"\"\"\n",
+ "total_contribution = 0\n",
+ "i = 0\n",
+ "for con in signal_constraints:\n",
+ " ctrb = exp.constraint_ctrb_to_conformance(\n",
+ " log=exp.event_log,\n",
+ " constraints=exp.constraints,\n",
+ " index=i\n",
+ " )\n",
+ " i +=1\n",
+ " total_contribution += ctrb\n",
+ " # Let's just show some traces\n",
+ " if i % 10 == 0:\n",
+ " print(f\"Contribution is: {ctrb}, for constraint {con}\")\n",
+ " \n",
+ "print(f\"Total distribution to the conformance loss is {total_contribution}\")\n",
+ "print(f\"Our total conformance loss is { 1 - conf_rate}\")\n",
+ "\"\"\""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/tutorial/tutorial.ipynb b/tutorial/tutorial.ipynb
index 3755a8d..7e7d8a1 100644
--- a/tutorial/tutorial.ipynb
+++ b/tutorial/tutorial.ipynb
@@ -106,7 +106,7 @@
"outputs": [
{
"data": {
- "image/png": "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94tyeLxlebiW5dl8v0CvlRBCCCFE8UIxKoQQQgghhBBCCJE0SKgQQgghhBBCCCFE0qCpH0IIkViIYzEvzn0JLPm7kkwIIYQQQhQnJFQIIURieSMH+45QcgkhhBBCiOKGpn4IIYQQQgghhBAiaZBQIYQQQgghhBBCiKRBQoUQIreUUxIoDYQQKhuEUB4VQuQ3EiqEEDnm2GOPbVu5cuXVrVu37qQ0KL5pIIRQ2SCE8qgQoiCQUCGEyHEF/8svvwy//fbbS3/yyScvnnLKKe2VBsUvDYQQKhuEUB4VQhQUEiqEEDmu4EeNGlWqe/fuZuTIkSW//fbbYQ0aNDhTaVB80kAIobJBCOVRIURBIqFCpAR///23+f3335UQCargTzrpJG8bf6nof/rpp9cPO+ywVkqD1E8DkTn2HTAXXXSRmT9/foEcf9WqVd7xv/zySyW2ygYhhPJosea6664zr732mhIihSmlJBD5yT333GNeeOGFjM/lypUz++yzjzn55JPN5ZdfbnbccccCOe8VV1xhxowZY/766y89hARV8AF8ZvuZZ545qk6dOm1mz549UWmQkDS439of1h6J8d3/rB1prZu1dFfWX2KtjbWdrM2z1s/atNBv0qx1sXaWtV2sbbD2rTVaASnbM165cqXp06ePGTt2rPn555+9bVWqVDH16tUzjLideuqpcR9r6dKlXvl39dVXm7333jvfr3XdunXe8Zs3b877qIJJZUOxo3///uaxxx7L+FypUiUvr51++umma9eupnTp0kokoTxaAEyaNMncf//9nlD+77//mp122skceeSRXtv+3HPPLZRrev31103JkiUL7fxCQkWB8PLLL5/xxRdfXDl9+vR6f/75ZwXbUC29ePHiEjVq1NhctWrVDbYzvbJatWpj58yZ89i8efN+02sSP3/88YdZvny5uemmmzK2ff/9997noUOHms8++8yUKVMm389LI6VixYp6AAmu4KMVfbt27cbsueeerX7//fe3lAYFngZbrN1n7Tlrq0PbS1rrZe1tJ1IgQLxuram1p6z95gSLT6y1tDY1JHxca+1Za+Os7cltWZuTqkLF119/bVq0aGHWr1/veSrcdtttXkfn119/9YSL9PT0lLlXGpZHHXWUmTFjhgo1lY9FFttmM7/99pu56667MrbZ9py58sorzfPPP28++OADU7ZsWSWUUB7NR8aPH2/atGljmjRpYp5++mmvvb1o0SIzZcoUT6AXhU5Na3gEtbBWw9pu1vawttDaEms8pImubbdIQkUSYhucOzzyyCN9RowYccW1115b+owzzjDdunXzlPgaNWqYPfbYwyxcuLCUzXAV58+fX9FmyuumTZt27X777fe7/e2Vc+fOnaB8EB94TYQbEfDGG2+YDh06mFdffdVceOGF+X7Ojh07eiYSX8GHK/rRo0fv0LZt2zerVavWctWqVVOVBgWaBggKt/H6W3sytP1kV0k97z53sNbW2gm06d22QdamWBto7cAgG7nj9CgO7zbeV61bt/bKq08//dTYsn6b72+//faUut8PP/zQm5oiVD4WddLS0rZrYzAQcsEFF5gXX3zRXHbZZUokoTyajzz++OOmTp06njBRosR/UQOYeiEKlSbW7rHWKJPv93BmnJDBYNVH1ihA35NQkSS89NJLFzZt2vSJhQsXlrvvvvvMWWed5bkKbfc099jDs2OOOcacffbZZsuWLWkjR46sdeutt47dZ599fpw3b147u9uvyhc558wzz/QKt5kzZ26znTnXjz76qNdRgOOOO8706NHD2ErCGwFklOSUU07xRI4oTDNh9NM+H7xkzHfffWf69u27zT54cDzxxBOe8ss0lPbt23uNGRo6zCPnGLhpH3300Rm/4VoGDx5sOnfu7E1ZCeDaH3nkEa8DU7t2bVXwmVT0Y8aMKd2mTZvxFSpUaLFu3bp3lQYFlgYLrDHq0zUiVHQ2/tSOD9xnll/7PCRSAK4CI6w9bW0ftz+eFi3dtpQv52h4LV682LzzzjvbiRSxYFoI5cyPP/7oeY7tvPPOnqs50zCyY8WKFWbAgAFe2bJ161az6667mvPPP98gmCMePPzww+bOO+80++677za/e+qppzwPtWinLMrkyZPNuHHjzNy5c83GjRvNwQcfbG644YaM+xoxYoS5++67vXPjOQKci3MG2Aa618lDwOHe6OxR9gqVj0WBTp06mauuuspMmzYtQ6i4/vrrvQGMmjVrmnvvvdfMnj3by3M33nij9z2eVORLygDb3jOHHHKI1/6oVatWxnEnTJhgpk+f7g1s0b5A8IP69et7U8Noq4Qhjw8fPtzYd8ObqsVg2DXXXOO5yAe89dZbnvs8+W/IkCHeHPvNmzebiRMnZkyPfffdd80zzzzj5X9G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GqQaeX2vhyXqQidPnuzZY489pgIx7+VZUtWLyVo22MZrUq36URzbHKeccop54YUX8hxQN7ewtOMxxxyz3RLqRTmPplIbJgd5NNftl0TXdckAq+6wAtWFF15YVOu6vJabrPpxDBu//vrrAg2oyfFD/J4saZxSQoXNxCMnTpxYN5HLkz777LO8hG8X0v16BZt74dPiWZZRTejcM2vWLPPJJ59ss450YZNdxR7ruf/+++9vVatWrWWbNm3Gjx07tkxhVPTRDnqeWj1xiBP5kQY9evTIWKIOgojsqNDr1q3ztm3cuNHccMMNZsiQIQlNg1QjN+91okCoDJ63SMp2QJ7qRZUNanNEmT9/vhe0OOotk0iGDRtmDjroIJX1KdaGyU37pTjx2muvma5duxbnOon+pbc86ZgxYwp0eVKOHzmvhIr8Zvr06YMWLFhwu30RSqJcFTT2PH///PPPh9l/zy+M+02WAo6GFxnx/PPPN3369DFvv/22t9woBUy4sHnllVe8RhvfMfp04oknRtPTPPfcc2bUqFFeo46lZm+55RYzZ84c8/3335ubb77Z22/GjBnm0Ucf9SIxR5cKe+KJJwiq6s0J3ibH2WsaPHiwWbFiBXO/zEUXXWTatm27zT4fffSRtw/rNMP+++9vbJp6+02ZMiXDjfC6667zlvHD7euRRx4plHc9r8991apVUytUqNCidevWE958882yiazo86uCT2QafP755947vHZtRgBmU65cOa/xeuSRR2Z0RjZs2OC5eF9yySWmfv36EikS/EwLEp4x5RvvAUGnKEPg3HPPJVZRxj4DBgww7777rlee4TJOJza8pNr48ePNzJkzvbKNVSKGDx/uNdYpY+w76W3v16+ftx9lJmVh7dq1ze233+51fpliwLzYv//+24vSTeeXkdYAOlMcd9KkSd5IftmyZb1RmE6dOqVkR6cg6kWVDcnb5pg9e7YZOHCg1w6AffbZx/NWqVevXsY18jywNWvWeEvD4oVwwQUXeK7W4XxIIDzq8/79+3vPi3xIXiPP1qnje2yTl4O6n+32vfDs8ccf9zxp+D2jvohSDzzwgNfGIE8S9BHxasSIEea9994zv/76q3eM4447znTv3n27ZRuXLl3qlR28T9xDMIq87777ml69epnffvvNa59wPXD//fcX6dgZxb0NU1TECYT5559/3ivfeN+u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F8yVV14poUIIIYQQSYuECiGEEIXKTTfddFjjxo33bNGiRR37sUt6evov9u8nphiJFjmlffv2pnr16koIIYQQQqQkEiqEEEIUKn369DnYmqlYseLm5s2bL+7SpUuVFi1a1DYSLTLl3nvvVSIIIYQQImWRUCGEECIpWLt2bak33nijFpYsosXHH39sBg8ebBYsWOB9rl27trHXY9q1a+d9njhxovn222/Ntddea/r27Ws++OADb/txxx1nevTosd3SpP/++695+umnzYQJE8ymTZu86Rfsd9BBB22z39atW82wYcPM8OHDzZo1a0y5cuXM0Ucfbe666y5TsmRJT6jYeeedvSkcAbNnzzYvv/yy+eGHH8wff/zhnbtr167e9QohhBBCSKgQQgghEidaFMg1TJkyJUOUaNOmjScYTJs2zYwYMSJDqJg5c6bp37+/GTt2rBczolmzZmblypVm0KBBZuTIkebLL780VapUyRAfWrVqZb766itz6aWXmt12283bp169euadd97xxA2w92Y6duxoRo0aZc466yxz1FFHmYULF5qffvrJEylg/PjxnsgRFipuvPFG89dff5kmTZqYGjVqeNdEwE725a8QQgghhIQKIYQoRtjO5TilQu7ITmgIixaVK1dOb9++/cbOnTuf0KhRo47GD8JZILz22mvmiCOO8LwasmLFihXmoosu8lbTCDj//PM9AYJtvXv39rY9++yz5t133zVff/11RhDNq666ytSvX99cd9115rPPPvO2cT57r975O3ToEPf1IqCUKVMm4/Nll11mDjjgADN06NCEChX/b+9OwGs+0/+P30cSEUVsY40wSkaNMh2qhFTQRku1ttqi9upM+0c7xNpSE1Nqi6SWoqYyat9rKzPGhSmpdiwNqkZRKrFTIY1EnN/3firnnxBbYvme5P26ruc62zffnDwni/NxP/ejIcvcuXP5eQAAAAQVAPAoWG8ui1lvNgOYiYfjwoULjunTp/voyJcvn7NKlSoFHtTn8vf3N6HBxo0bTZXC7fTs2TPD7Ro1akhISIipakgLKubMmSPPPfdchp0+tEKiTZs2MnjwYLNco2jRoiagCAgIuKeQQqUPKVSePHmkevXqZivTh0W/hn379klu/pnQ3wn8pAIAkD0EFQBw71KsN4XX9MrOnTuL6WBKHr6kpCTHrl27HntQ5+/fv7+p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\n",
+ "image/png": "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94tyeLxlebiW5dl8v0CvlRBCCCFE8UIxKoQQQgghhBBCCJE0SKgQQgghhBBCCCFE0qCpH0IIkViIYzEvzn0JLPm7kkwIIYQQQhQnJFQIIURieSMH+45QcgkhhBBCiOKGpn4IIYQQQgghhBAiaZBQIYQQQgghhBBCiKRBQoUQIreUUxIoDYQQKhuEUB4VQuQ3EiqEEDnm2GOPbVu5cuXVrVu37qQ0KL5pIIRQ2SCE8qgQoiCQUCGEyHEF/8svvwy//fbbS3/yyScvnnLKKe2VBsUvDYQQKhuEUB4VQhQUEiqEEDmu4EeNGlWqe/fuZuTIkSW//fbbYQ0aNDhTaVB80kAIobJBCOVRIURBIqFCpAR///23+f3335UQCargTzrpJG8bf6nof/rpp9cPO+ywVkqD1E8DkTn2HTAXXXSRmT9/foEcf9WqVd7xv/zySyW2ygYhhPJosea6664zr732mhIihSmlJBD5yT333GNeeOGFjM/lypUz++yzjzn55JPN5ZdfbnbccccCOe8VV1xhxowZY/766y89hARV8AF8ZvuZZ545qk6dOm1mz549UWmQkDS439of1h6J8d3/rB1prZu1dFfWX2KtjbWdrM2z1s/atNBv0qx1sXaWtV2sbbD2rTVaASnbM165cqXp06ePGTt2rPn555+9bVWqVDH16tUzjLideuqpcR9r6dKlXvl39dVXm7333jvfr3XdunXe8Zs3b877qIJJZUOxo3///uaxxx7L+FypUiUvr51++umma9eupnTp0kokoTxaAEyaNMncf//9nlD+77//mp122skceeSRXtv+3HPPLZRrev31103JkiUL7fxCQkWB8PLLL5/xxRdfXDl9+vR6f/75ZwXbUC29ePHiEjVq1NhctWrVDbYzvbJatWpj58yZ89i8efN+02sSP3/88YdZvny5uemmmzK2ff/9997noUOHms8++8yUKVMm389LI6VixYp6AAmu4KMVfbt27cbsueeerX7//fe3lAYFngZbrN1n7Tlrq0PbS1rrZe1tJ1IgQLxuram1p6z95gSLT6y1tDY1JHxca+1Za+Os7cltWZuTqkLF119/bVq0aGHWr1/veSrcdtttXkfn119/9YSL9PT0lLlXGpZHHXWUmTFjhgo1lY9FFttmM7/99pu56667MrbZ9py58sorzfPPP28++OADU7ZsWSWUUB7NR8aPH2/atGljmjRpYp5++mmvvb1o0SIzZcoUT6AXhU5Na3gEtbBWw9pu1vawttDaEms8pImubbdIQkUSYhucOzzyyCN9RowYccW1115b+owzzjDdunXzlPgaNWqYPfbYwyxcuLCUzXAV58+fX9FmyuumTZt27X777fe7/e2Vc+fOnaB8EB94TYQbEfDGG2+YDh06mFdffdVceOGF+X7Ojh07eiYSX8GHK/rRo0fv0LZt2zerVavWctWqVVOVBgWaBggKt/H6W3sytP1kV0k97z53sNbW2gm06d22QdamWBto7cAgG7nj9CgO7zbeV61bt/bKq08//dTYsn6b72+//faUut8PP/zQm5oiVD4WddLS0rZrYzAQcsEFF5gXX3zRXHbZZUokoTyajzz++OOmTp06njBRosR/UQOYeiEKlSbW7rHWKJPv93BmnJDBYNVH1ihA35NQkSS89NJLFzZt2vSJhQsXlrvvvvvMWWed5bkKbfc099jDs2OOOcacffbZZsuWLWkjR46sdeutt47dZ599fpw3b147u9uvyhc558wzz/QKt5kzZ26znTnXjz76qNdRgOOOO8706NHD2ErCGwFklOSUU07xRI4oTDNh9NM+H7xkzHfffWf69u27zT54cDzxxBOe8ss0lPbt23uNGRo6zCPnGLhpH3300Rm/4VoGDx5sOnfu7E1ZCeDaH3nkEa8DU7t2bVXwmVT0Y8aMKd2mTZvxFSpUaLFu3bp3lQYFlgYLrDHq0zUiVHQ2/tSOD9xnll/7PCRSAK4CI6w9bW0ftz+eFi3dtpQv52h4LV682LzzzjvbiRSxYFoI5cyPP/7oeY7tvPPOnqs50zCyY8WKFWbAgAFe2bJ161az6667mvPPP98gmCMePPzww+bOO+80++677za/e+qppzwPtWinLMrkyZPNuHHjzNy5c83GjRvNwQcfbG644YaM+xoxYoS5++67vXPjOQKci3MG2Aa618lDwOHe6OxR9gqVj0WBTp06mauuuspMmzYtQ6i4/vrrvQGMmjVrmnvvvdfMnj3by3M33nij9z2eVORLygDb3jOHHHKI1/6oVatWxnEnTJhgpk+f7g1s0b5A8IP69et7U8Noq4Qhjw8fPtzYd8ObqsVg2DXXXOO5yAe89dZbnvs8+W/IkCHeHPvNmzebiRMnZkyPfffdd80zzzzj5X9G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GqQaeX2vhyXqQidPnuzZY489pgIx7+VZUtWLyVo22MZrUq36URzbHKeccop54YUX8hxQN7ewtOMxxxyz3RLqRTmPplIbJgd5NNftl0TXdckAq+6wAtWFF15YVOu6vJabrPpxDBu//vrrAg2oyfFD/J4saZxSQoXNxCMnTpxYN5HLkz777LO8hG8X0v16BZt74dPiWZZRTejcM2vWLPPJJ59ss450YZNdxR7ruf/+++9vVatWrWWbNm3Gjx07tkxhVPTRDnqeWj1xiBP5kQY9evTIWKIOgojsqNDr1q3ztm3cuNHccMMNZsiQIQlNg1QjN+91okCoDJ63SMp2QJ7qRZUNanNEmT9/vhe0OOotk0iGDRtmDjroIJX1KdaGyU37pTjx2muvma5duxbnOon+pbc86ZgxYwp0eVKOHzmvhIr8Zvr06YMWLFhwu30RSqJcFTT2PH///PPPh9l/zy+M+02WAo6GFxnx/PPPN3369DFvv/22t9woBUy4sHnllVe8RhvfMfp04oknRtPTPPfcc2bUqFFeo46lZm+55RYzZ84c8/3335ubb77Z22/GjBnm0Ucf9SIxR5cKe+KJJwiq6s0J3ibH2WsaPHiwWbFiBXO/zEUXXWTatm27zT4fffSRtw/rNMP+++9vbJp6+02ZMiXDjfC6667zlvHD7euRRx4plHc9r8991apVUytUqNCidevWE958882yiazo86uCT2QafP755947vHZtRgBmU65cOa/xeuSRR2Z0RjZs2OC5eF9yySWmfv36EikS/EwLEp4x5RvvAUGnKEPg3HPPJVZRxj4DBgww7777rlee4TJOJza8pNr48ePNzJkzvbKNVSKGDx/uNdYpY+w76W3v16+ftx9lJmVh7dq1ze233+51fpliwLzYv//+24vSTeeXkdYAOlMcd9KkSd5IftmyZb1RmE6dOqVkR6cg6kWVDcnb5pg9e7YZOHCg1w6AffbZx/NWqVevXsY18jywNWvWeEvD4oVwwQUXeK7W4XxIIDzq8/79+3vPi3xIXiPP1qnje2yTl4O6n+32vfDs8ccf9zxp+D2jvohSDzzwgNfGIE8S9BHxasSIEea9994zv/76q3eM4447znTv3n27ZRuXLl3qlR28T9xDMIq87777ml69epnffvvNa59wPXD//fcX6dgZxb0NU1TECYT5559/3ivfeN+u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F8yVV14poUIIIYQQSYuECiGEEIXKTTfddFjjxo33bNGiRR37sUt6evov9u8nphiJFjmlffv2pnr16koIIYQQQqQkEiqEEEIUKn369DnYmqlYseLm5s2bL+7SpUuVFi1a1DYSLTLl3nvvVSIIIYQQImWRUCGEECIpWLt2bak33nijFpYsosXHH39sBg8ebBYsWOB9rl27trHXY9q1a+d9njhxovn222/Ntddea/r27Ws++OADb/txxx1nevTosd3SpP/++695+umnzYQJE8ymTZu86Rfsd9BBB22z39atW82wYcPM8OHDzZo1a0y5cuXM0Ucfbe666y5TsmRJT6jYeeedvSkcAbNnzzYvv/yy+eGHH8wff/zhnbtr167e9QohhBBCSKgQQgghEidaFMg1TJkyJUOUaNOmjScYTJs2zYwYMSJDqJg5c6bp37+/GTt2rBczolmzZmblypVm0KBBZuTIkebLL780VapUyRAfWrVqZb766itz6aWXmt12283bp169euadd97xxA2w92Y6duxoRo0aZc466yxz1FFHmYULF5qffvrJEylg/PjxnsgRFipuvPFG89dff5kmTZqYGjVqeNdEwE725a8QQgghhIQKIYQoRtjO5TilQu7ITmgIixaVK1dOb9++/cbOnTuf0KhRo47GD8JZILz22mvmiCOO8LwasmLFihXmoosu8lbTCDj//PM9AYJtvXv39rY9++yz5t133zVff/11RhDNq666ytSvX99cd9115rPPPvO2cT57r975O3ToEPf1IqCUKVMm4/Nll11mDjjgADN06NCEChX/b+9OwGs+0/+P30cSEUVsY40wSkaNMh2qhFTQRku1ttqi9upM+0c7xNpSE1Nqi6SWoqYyat9rKzPGhSmpdiwNqkZRKrFTIY1EnN/3firnnxBbYvme5P26ruc62zffnDwni/NxP/ejIcvcuXP5eQAAAAQVAPAoWG8ui1lvNgOYiYfjwoULjunTp/voyJcvn7NKlSoFHtTn8vf3N6HBxo0bTZXC7fTs2TPD7Ro1akhISIipakgLKubMmSPPPfdchp0+tEKiTZs2MnjwYLNco2jRoiagCAgIuKeQQqUPKVSePHmkevXqZivTh0W/hn379klu/pnQ3wn8pAIAkD0EFQBw71KsN4XX9MrOnTuL6WBKHr6kpCTHrl27HntQ5+/fv7+p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",
"text/plain": [
""
]
@@ -488,7 +488,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.10.2"
+ "version": "3.12.1"
}
},
"nbformat": 4,