From baede64f2e31428901b6d000b9ae988d243d8f31 Mon Sep 17 00:00:00 2001 From: Daniel Neugebauer Date: Thu, 7 Mar 2019 12:32:23 +0100 Subject: [PATCH] Fix cases where user opinions contain statements that do not occur in arguments --- dabasco/adf/import_strass.py | 6 +- dabasco/adf/tests/test_import_strass.py | 99 ++++++++++++++++++++++++ dabasco/af/import_wyner.py | 4 +- dabasco/af/tests/test_af_import_wyner.py | 91 ++++++++++++++++++++++ dabasco/aspic/export_toast.py | 4 +- dabasco/aspic/tests/test_export_toast.py | 60 ++++++++++++++ 6 files changed, 258 insertions(+), 6 deletions(-) diff --git a/dabasco/adf/import_strass.py b/dabasco/adf/import_strass.py index 4d9d6b0..26e7d88 100644 --- a/dabasco/adf/import_strass.py +++ b/dabasco/adf/import_strass.py @@ -18,8 +18,10 @@ def import_adf(dbas_graph, opinion, opinion_strict): adf = ADF() # Get accepted/rejected statements from opinion - user_accepted_statements = opinion.get_accepted_statements() if opinion else [] - user_rejected_statements = opinion.get_rejected_statements() if opinion else [] + user_accepted_statements = opinion.get_accepted_statements().intersection(dbas_graph.statements)\ + if opinion else set() + user_rejected_statements = opinion.get_rejected_statements().intersection(dbas_graph.statements)\ + if opinion else set() # Setup statement acceptance functions for statement in dbas_graph.statements: diff --git a/dabasco/adf/tests/test_import_strass.py b/dabasco/adf/tests/test_import_strass.py index 7619cdb..23c456a 100644 --- a/dabasco/adf/tests/test_import_strass.py +++ b/dabasco/adf/tests/test_import_strass.py @@ -423,6 +423,105 @@ def test_discussion3_objective(self): self.assertTrue(adf_reference.is_equivalent_to(adf_result)) + def test_discussion2_user99_defeasible(self): + discussion_id = 2 + user_id = 99 + strict_opinion = False + + dbas_discussion_json = { + "inferences": [ + {"conclusion": 1, "id": 1, "is_supportive": True, "premises": [2]}, + {"conclusion": 1, "id": 2, "is_supportive": False, "premises": [3]}, + {"conclusion": 2, "id": 3, "is_supportive": False, "premises": [4]} + ], + "nodes": [1, 2, 3, 4, 5], + "undercuts": [ + {"conclusion": 2, "id": 4, "premises": [5]} + ] + } + dbas_user_json = { + "accepted_statements_via_click": [3, 4, 99], + "marked_arguments": [], + "marked_statements": [], + "rejected_arguments": [], + "rejected_statements_via_click": [5, 999], + } + + dbas_discussion = import_dbas_graph(discussion_id=discussion_id, graph_export=dbas_discussion_json) + dbas_user = import_dbas_user(discussion_id=discussion_id, user_id=user_id, user_export=dbas_user_json) + adf_result = import_adf(dbas_discussion, dbas_user, strict_opinion) + + adf_reference = ADF() + + # D-BAS Statements + adf_reference.add_statement('s1', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ns1')), + ADFNode(ADFNode.OR, ADFNode(ADFNode.LEAF, 'i1')) + ])) + adf_reference.add_statement('ns1', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 's1')), + ADFNode(ADFNode.OR, ADFNode(ADFNode.LEAF, 'i2')) + ])) + adf_reference.add_statement('s2', ADFNode(ADFNode.LEAF, ADFNode.CONSTANT_FALSE)) + adf_reference.add_statement('ns2', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 's2')), + ADFNode(ADFNode.OR, ADFNode(ADFNode.LEAF, 'i3')) + ])) + adf_reference.add_statement('s3', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ns3')), + ADFNode(ADFNode.OR, ADFNode(ADFNode.LEAF, 'ua3')) + ])) + adf_reference.add_statement('ns3', ADFNode(ADFNode.LEAF, ADFNode.CONSTANT_FALSE)) + adf_reference.add_statement('s4', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ns4')), + ADFNode(ADFNode.OR, ADFNode(ADFNode.LEAF, 'ua4')) + ])) + adf_reference.add_statement('ns4', ADFNode(ADFNode.LEAF, ADFNode.CONSTANT_FALSE)) + adf_reference.add_statement('s5', ADFNode(ADFNode.LEAF, ADFNode.CONSTANT_FALSE)) + adf_reference.add_statement('ns5', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 's5')), + ADFNode(ADFNode.OR, ADFNode(ADFNode.LEAF, 'ur5')) + ])) + + # User opinion + adf_reference.add_statement('ua3', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ns3')), + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'nua3'))])) + adf_reference.add_statement('nua3', ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ua3'))) + adf_reference.add_statement('ua4', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ns4')), + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'nua4'))])) + adf_reference.add_statement('nua4', ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ua4'))) + adf_reference.add_statement('ur5', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 's5')), + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'nur5'))])) + adf_reference.add_statement('nur5', ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ur5'))) + + # D-BAS Inferences + adf_reference.add_statement('i1', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ns1')), + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ni1')), + ADFNode(ADFNode.LEAF, 's2')])) + adf_reference.add_statement('ni1', ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'i1'))) + adf_reference.add_statement('i2', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 's1')), + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ni2')), + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'i4')), + ADFNode(ADFNode.LEAF, 's3')])) + adf_reference.add_statement('ni2', ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'i2'))) + adf_reference.add_statement('i3', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 's2')), + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ni3')), + ADFNode(ADFNode.LEAF, 's4')])) + adf_reference.add_statement('ni3', ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'i3'))) + adf_reference.add_statement('i4', ADFNode(ADFNode.AND, [ + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'i2')), + ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'ni4')), + ADFNode(ADFNode.LEAF, 's5')])) + adf_reference.add_statement('ni4', ADFNode(ADFNode.NOT, ADFNode(ADFNode.LEAF, 'i4'))) + + self.assertTrue(adf_reference.is_equivalent_to(adf_result)) + if __name__ == '__main__': unittest.main() diff --git a/dabasco/af/import_wyner.py b/dabasco/af/import_wyner.py index b231d62..9411fef 100644 --- a/dabasco/af/import_wyner.py +++ b/dabasco/af/import_wyner.py @@ -32,8 +32,8 @@ def import_af_wyner(dbas_graph, opinion, opinion_strict): user_rejected_statements = set() user_accepted_statements = set() if opinion: - user_rejected_statements = opinion.get_rejected_statements() - user_accepted_statements = opinion.get_accepted_statements() + user_rejected_statements = opinion.get_rejected_statements().intersection(dbas_graph.statements) + user_accepted_statements = opinion.get_accepted_statements().intersection(dbas_graph.statements) # Add two arguments for each statement for statement in dbas_graph.statements: diff --git a/dabasco/af/tests/test_af_import_wyner.py b/dabasco/af/tests/test_af_import_wyner.py index d022f12..47ac3ee 100644 --- a/dabasco/af/tests/test_af_import_wyner.py +++ b/dabasco/af/tests/test_af_import_wyner.py @@ -622,6 +622,97 @@ def test_discussion2_user3_strict_opinion(self): self.assertTrue(af_reference.is_equivalent_to(af_result)) + def test_discussion2_user99_weak_opinion(self): + discussion_id = 2 + user_id = 99 + assumptions_strict = False + + dbas_discussion_json = { + "inferences": [ + {"conclusion": 1, "id": 1, "is_supportive": True, "premises": [2]}, + {"conclusion": 1, "id": 2, "is_supportive": False, "premises": [3]}, + {"conclusion": 2, "id": 3, "is_supportive": False, "premises": [4]} + ], + "nodes": [1, 2, 3, 4, 5], + "undercuts": [ + {"conclusion": 2, "id": 4, "premises": [5]} + ] + } + dbas_user_json = { + "accepted_statements_via_click": [3, 4, 99], + "marked_arguments": [], + "marked_statements": [], + "rejected_arguments": [], + "rejected_statements_via_click": [5, 999], + } + + dbas_discussion = import_dbas_graph(discussion_id=discussion_id, graph_export=dbas_discussion_json) + dbas_user = import_dbas_user(discussion_id=discussion_id, user_id=user_id, user_export=dbas_user_json) + af_result = import_af_wyner(dbas_discussion, opinion=dbas_user, opinion_strict=assumptions_strict) + + af_reference = AF(17) + arg_1 = af_result.get_argument_for_name(LITERAL_PREFIX_STATEMENT + '1') + arg_neg1 = af_result.get_argument_for_name(LITERAL_PREFIX_NOT + LITERAL_PREFIX_STATEMENT + '1') + arg_2 = af_result.get_argument_for_name(LITERAL_PREFIX_STATEMENT + '2') + arg_neg2 = af_result.get_argument_for_name(LITERAL_PREFIX_NOT + LITERAL_PREFIX_STATEMENT + '2') + arg_3 = af_result.get_argument_for_name(LITERAL_PREFIX_STATEMENT + '3') + arg_neg3 = af_result.get_argument_for_name(LITERAL_PREFIX_NOT + LITERAL_PREFIX_STATEMENT + '3') + arg_4 = af_result.get_argument_for_name(LITERAL_PREFIX_STATEMENT + '4') + arg_neg4 = af_result.get_argument_for_name(LITERAL_PREFIX_NOT + LITERAL_PREFIX_STATEMENT + '4') + arg_5 = af_result.get_argument_for_name(LITERAL_PREFIX_STATEMENT + '5') + arg_neg5 = af_result.get_argument_for_name(LITERAL_PREFIX_NOT + LITERAL_PREFIX_STATEMENT + '5') + arg_r1 = af_result.get_argument_for_name(LITERAL_PREFIX_INFERENCE_RULE + '1') + arg_r2 = af_result.get_argument_for_name(LITERAL_PREFIX_INFERENCE_RULE + '2') + arg_r3 = af_result.get_argument_for_name(LITERAL_PREFIX_INFERENCE_RULE + '3') + arg_r4 = af_result.get_argument_for_name(LITERAL_PREFIX_INFERENCE_RULE + '4') + arg_u3 = af_result.get_argument_for_name(DUMMY_LITERAL_NAME_OPINION + '_' + '3') + arg_u4 = af_result.get_argument_for_name(DUMMY_LITERAL_NAME_OPINION + '_' + '4') + arg_uneg5 = af_result.get_argument_for_name(DUMMY_LITERAL_NAME_OPINION + '_' + LITERAL_PREFIX_NOT + '5') + + # Attacks between statement args + af_reference.set_attack(arg_1, arg_neg1, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg1, arg_1, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_2, arg_neg2, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg2, arg_2, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_3, arg_neg3, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg3, arg_3, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_4, arg_neg4, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg4, arg_4, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_5, arg_neg5, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg5, arg_5, AF.DEFINITE_ATTACK) + + # Undermining attacks by negated premises + af_reference.set_attack(arg_neg2, arg_r1, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg3, arg_r2, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg4, arg_r3, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg5, arg_r4, AF.DEFINITE_ATTACK) + + # Rebutting attacks between rules and negated conclusions + af_reference.set_attack(arg_r1, arg_neg1, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg1, arg_r1, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_r2, arg_1, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_1, arg_r2, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_r3, arg_2, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_2, arg_r3, AF.DEFINITE_ATTACK) + + # Undercutting attacks + af_reference.set_attack(arg_r4, arg_r2, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_r2, arg_r4, AF.DEFINITE_ATTACK) + + # Attacks between user opinion args and negated statements + af_reference.set_attack(arg_u3, arg_neg3, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg3, arg_u3, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_u4, arg_neg4, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_neg4, arg_u4, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_uneg5, arg_5, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_5, arg_uneg5, AF.DEFINITE_ATTACK) + + # Rebutting attacks between rule arguments with conflicting conclusions + af_reference.set_attack(arg_r1, arg_r2, AF.DEFINITE_ATTACK) + af_reference.set_attack(arg_r2, arg_r1, AF.DEFINITE_ATTACK) + + self.assertTrue(af_reference.is_equivalent_to(af_result)) + if __name__ == '__main__': unittest.main() diff --git a/dabasco/aspic/export_toast.py b/dabasco/aspic/export_toast.py index 214e64e..08e509e 100644 --- a/dabasco/aspic/export_toast.py +++ b/dabasco/aspic/export_toast.py @@ -50,8 +50,8 @@ def export_toast(dbas_graph, opinion_type, opinion, assumptions_type, assumption if opinion: if opinion_type in [DABASCO_INPUT_KEYWORD_OPINION_WEAK, DABASCO_INPUT_KEYWORD_OPINION_STRONG]: aspic_axioms.append(DUMMY_LITERAL_NAME_OPINION) - user_accepted_statements = opinion.get_accepted_statements() - user_rejected_statements = opinion.get_rejected_statements() + user_accepted_statements = opinion.get_accepted_statements().intersection(dbas_graph.statements) + user_rejected_statements = opinion.get_rejected_statements().intersection(dbas_graph.statements) opinion_rule_names = [] if opinion_type == DABASCO_INPUT_KEYWORD_OPINION_STRICT: for statement in user_accepted_statements: diff --git a/dabasco/aspic/tests/test_export_toast.py b/dabasco/aspic/tests/test_export_toast.py index fc321c9..b74cd78 100644 --- a/dabasco/aspic/tests/test_export_toast.py +++ b/dabasco/aspic/tests/test_export_toast.py @@ -1062,6 +1062,66 @@ def test_discussion2_strict_user2_strong_assumptions_no_bias(self): self.assertEqual(set(aspic_result["rulePrefs"]), reference_rule_prefs) self.assertEqual(aspic_result["semantics"], semantics) + def test_discussion2_strong_user99_no_assumptions(self): + discussion_id = 2 + user_id = 99 + opinion_type = "strong" + assumptions_type = None + assumptions_bias = None + semantics = "preferred" + + dbas_discussion_json = { + "inferences": [ + {"conclusion": 1, "id": 1, "is_supportive": True, "premises": [2]}, + {"conclusion": 1, "id": 2, "is_supportive": False, "premises": [3]}, + {"conclusion": 2, "id": 3, "is_supportive": False, "premises": [4]} + ], + "nodes": [1, 2, 3, 4, 5], + "undercuts": [ + {"conclusion": 2, "id": 4, "premises": [5]} + ] + } + dbas_user_json = { + "accepted_statements_via_click": [3, 4, 99], + "marked_arguments": [], + "marked_statements": [], + "rejected_arguments": [], + "rejected_statements_via_click": [5, 999], + } + + dbas_discussion = import_dbas_graph(discussion_id=discussion_id, graph_export=dbas_discussion_json) + dbas_user = import_dbas_user(discussion_id=discussion_id, user_id=user_id, user_export=dbas_user_json) + + aspic_result = export_toast(dbas_graph=dbas_discussion, + opinion_type=opinion_type, + opinion=dbas_user, + assumptions_type=assumptions_type, + assumptions_bias=assumptions_bias, + semantics=semantics) + + reference_assumptions = set() + reference_axioms = {"opinion_dummy"} + reference_contrariness = set() + reference_kbPrefs = set() + reference_rules = { + "[ua3] opinion_dummy=>3", + "[ua4] opinion_dummy=>4", + "[ur5] opinion_dummy=>~5", + "[i1] 2=>1", + "[i2] 3=>~1", + "[i3] 4=>~2", + "[i4] 5=>~[i2]" + } + reference_rulePrefs = set() + + self.assertEqual(set(aspic_result["assumptions"]), reference_assumptions) + self.assertEqual(set(aspic_result["axioms"]), reference_axioms) + self.assertEqual(set(aspic_result["contrariness"]), reference_contrariness) + self.assertEqual(set(aspic_result["kbPrefs"]), reference_kbPrefs) + self.assertEqual(set(aspic_result["rules"]), reference_rules) + self.assertEqual(set(aspic_result["rulePrefs"]), reference_rulePrefs) + self.assertEqual(aspic_result["semantics"], semantics) + if __name__ == '__main__': unittest.main()