diff --git a/pyqpanda-algorithm/pyqpanda_alg/QARM/__init__.py b/pyqpanda-algorithm/pyqpanda_alg/QARM/__init__.py index b0980243..886fee67 100644 --- a/pyqpanda-algorithm/pyqpanda_alg/QARM/__init__.py +++ b/pyqpanda-algorithm/pyqpanda_alg/QARM/__init__.py @@ -16,6 +16,6 @@ less than the predetermined threshold from the superposition quantum states. ''' -from .qarm import QuantumAssociationRulesMining +from .complete_rules import QuantumAssociationRulesMining __all__ = ['QuantumAssociationRulesMining'] \ No newline at end of file diff --git a/pyqpanda-algorithm/pyqpanda_alg/QARM/complete_rules.py b/pyqpanda-algorithm/pyqpanda_alg/QARM/complete_rules.py new file mode 100644 index 00000000..6eee2262 --- /dev/null +++ b/pyqpanda-algorithm/pyqpanda_alg/QARM/complete_rules.py @@ -0,0 +1,44 @@ +from itertools import combinations + +from .qarm import QuantumAssociationRulesMining as _QuantumAssociationRulesMining + + +class QuantumAssociationRulesMining(_QuantumAssociationRulesMining): + """QARM implementation with complete association-rule enumeration.""" + + def _get_all_conf(self, qlist, clist, position, show, file_name, machine_type): + fn, fn_dict = self._fk_result( + qlist, clist, position, show, file_name, machine_type + ) + if len(fn) < 2: + return None + + support_by_itemset = { + frozenset(itemset): data[1] + for itemset, data in fn_dict.items() + } + conf_dict = {} + for level in fn[1:]: + for itemset in level: + itemset_set = frozenset(itemset) + supp_xy = support_by_itemset[itemset_set] + ordered_items = sorted(itemset_set) + for cause_size in range(1, len(ordered_items)): + for cause_items in combinations(ordered_items, cause_size): + cause = frozenset(cause_items) + supp_x = support_by_itemset[cause] + conf = self._conf_x_y(supp_xy, supp_x) + if conf >= self.min_conf: + effect = itemset_set - cause + key = self._get_conf_key(cause, effect) + conf_dict[key] = conf + return conf_dict + + def _get_conf_key(self, cause, effect): + cause_str = ','.join( + self.items_dict[item] for item in sorted(cause) + ) + effect_str = ','.join( + self.items_dict[item] for item in sorted(effect) + ) + return cause_str + '->' + effect_str diff --git a/test/QARM/Test_qarm_complete_rules.py b/test/QARM/Test_qarm_complete_rules.py new file mode 100644 index 00000000..461a6ae5 --- /dev/null +++ b/test/QARM/Test_qarm_complete_rules.py @@ -0,0 +1,66 @@ +from pyqpanda_alg.QARM import QuantumAssociationRulesMining + + +def _fixture_qarm(min_conf=0.0): + qarm = QuantumAssociationRulesMining( + [ + ['A', 'B', 'C'], + ['A', 'B', 'C'], + ['A', 'B'], + ['A', 'C'], + ], + min_support=0.5, + min_conf=min_conf, + ) + frequent_levels = [ + [(1,), (2,), (3,)], + [(1, 2), (1, 3), (2, 3)], + [(1, 2, 3)], + ] + frequent_data = { + (1,): [[0, 1, 2, 3], 1.0], + (2,): [[0, 1, 2], 0.75], + (3,): [[0, 1, 3], 0.75], + (1, 2): [[0, 1, 2], 0.75], + (1, 3): [[0, 1, 3], 0.75], + (2, 3): [[0, 1], 0.5], + (1, 2, 3): [[0, 1], 0.5], + } + qarm._fk_result = lambda *_args, **_kwargs: (frequent_levels, frequent_data) + return qarm + + +def test_get_all_conf_enumerates_all_nonempty_proper_subsets(): + qarm = _fixture_qarm() + result = qarm._get_all_conf(None, None, 0, None, '', 'CPU') + + assert result == { + 'A->B': 0.75, + 'B->A': 1.0, + 'A->C': 0.75, + 'C->A': 1.0, + 'B->C': 0.67, + 'C->B': 0.67, + 'A->B,C': 0.5, + 'B->A,C': 0.67, + 'C->A,B': 0.67, + 'A,B->C': 0.67, + 'A,C->B': 0.67, + 'B,C->A': 1.0, + } + + +def test_get_all_conf_applies_confidence_threshold_to_higher_order_rules(): + qarm = _fixture_qarm(min_conf=0.8) + result = qarm._get_all_conf(None, None, 0, None, '', 'CPU') + + assert result == { + 'B->A': 1.0, + 'C->A': 1.0, + 'B,C->A': 1.0, + } + + +def test_get_conf_key_is_deterministic_for_unordered_sets(): + qarm = _fixture_qarm() + assert qarm._get_conf_key(frozenset({3, 1}), frozenset({2})) == 'A,C->B'