def test_penalty_model_insert_retrieve(self):
        conn = self.clean_connection

        graph = nx.path_graph(3)
        decision_variables = (0, 2)
        feasible_configurations = {(-1, -1): 0., (+1, +1): 0.}
        spec = pm.Specification(graph, decision_variables,
                                feasible_configurations, dimod.SPIN)

        linear = {v: 0 for v in graph}
        quadratic = {edge: -1 for edge in graph.edges}
        model = dimod.BinaryQuadraticModel(linear,
                                           quadratic,
                                           0.0,
                                           vartype=dimod.SPIN)

        widget = pm.PenaltyModel.from_specification(spec, model, 2., -2)

        with conn as cur:
            pmc.insert_penalty_model(cur, widget)

        with conn as cur:
            pms = list(pmc.iter_penalty_model_from_specification(cur, spec))

            self.assertEqual(len(pms), 1)
            widget_, = pms
            self.assertEqual(widget_, widget)
    def test_penalty_model_classical_gap_insert_retrieve(self):
        """Verify that classical gap constraint searches work in the database.
        """
        conn = self.clean_connection

        # Set up specifications for widget
        decision_variables = ['a', 'b', 'c']
        graph = nx.path_graph(decision_variables)
        and_gate_configurations = {
            (-1, -1, -1): 0,
            (-1, +1, -1): 0,
            (+1, -1, -1): 0,
            (+1, +1, +1): 0
        }
        linear = {v: 0 for v in graph}
        quadratic = {edge: -1 for edge in graph.edges}
        model = dimod.BinaryQuadraticModel(linear,
                                           quadratic,
                                           0.0,
                                           vartype=dimod.SPIN)

        spec = pm.Specification(graph, decision_variables,
                                and_gate_configurations, dimod.SPIN)
        widget = pm.PenaltyModel.from_specification(spec, model, 2., -2)

        # Insert widget into database
        with conn as cur:
            pmc.insert_penalty_model(cur, widget)

        # Test specifications with varying classical gap sizes
        max_gap = 2
        spec_same_gap = pm.Specification(graph,
                                         decision_variables,
                                         and_gate_configurations,
                                         dimod.SPIN,
                                         min_classical_gap=max_gap)
        spec_smaller_gap = pm.Specification(graph,
                                            decision_variables,
                                            and_gate_configurations,
                                            dimod.SPIN,
                                            min_classical_gap=max_gap - 1)
        spec_larger_gap = pm.Specification(graph,
                                           decision_variables,
                                           and_gate_configurations,
                                           dimod.SPIN,
                                           min_classical_gap=max_gap + 1)

        # Find in database
        with conn as cur:
            # Search database for penalty models matching specifications
            pms_same_gap = list(
                pmc.iter_penalty_model_from_specification(cur, spec_same_gap))
            pms_smaller_gap = list(
                pmc.iter_penalty_model_from_specification(
                    cur, spec_smaller_gap))
            pms_larger_gap = list(
                pmc.iter_penalty_model_from_specification(
                    cur, spec_larger_gap))

            # Test specification that uses the max classical gap as its min_classical_gap
            self.assertEqual(len(pms_same_gap), 1,
                             'Using max gap should return a penalty model.')
            widget_same_gap_, = pms_same_gap
            self.assertEqual(widget_same_gap_, widget)

            # Specification uses a gap that is smaller than the expected max classical gap
            self.assertEqual(
                len(pms_smaller_gap), 1,
                'Using a gap that is less than the max gap'
                ' should return a penalty model.')
            widget_smaller_gap_, = pms_smaller_gap
            self.assertEqual(widget_smaller_gap_, widget)

            # Specification uses a gap that is larger than the expected max classical gap
            # Note: classical gap constraint shouldn't be satisfied in this case
            self.assertEqual(
                len(pms_larger_gap), 0,
                'Using a gap that exceeds the max gap should'
                ' not return a penalty model.')