Пример #1
0
    def _project_tbn_to_column_matrix(tbn: Tbn) -> np.array:
        monomer_types = list(tbn.monomer_types())
        limiting_domain_types = list(tbn.limiting_domain_types())
        monomer_matrix = np.array(
            [[-monomer.net_count(domain) for domain in limiting_domain_types]
             for monomer in monomer_types], np.int64).T

        return monomer_matrix
Пример #2
0
    def test_from_string(self):
        with self.subTest("single monomer example"):
            self.assertEqual(Tbn({Monomer.from_string("a"): 1}), Tbn.from_string("a"))

        with self.subTest("single monomer type, multiple monomer example"):
            self.assertEqual(Tbn({Monomer.from_string("a"): 2}), Tbn.from_string("2[a]"))

        with self.subTest("testing from_string with example from stablegen.net/help"):
            example_text = \
                """
                a*:b1 b*
                a b:b2 >m1
                a* >m2
                b*
                """
            example_tbn = Tbn({
                Monomer.from_string("a* b*"): 1,
                Monomer.from_string("a b", "m1"): 1,
                Monomer.from_string("a*", "m2"): 1,
                Monomer.from_string("b*"): 1,
            })
            self.assertEqual(example_tbn, Tbn.from_string(example_text))

        with self.subTest("testing from_string with multisets"):
            multiset_text = \
                """
                2[ 3(a*) a b ]
                [ c ]
                5[ a a:favorite_a b >bob ]
                7[ b a b b ]
                b a b b b*
                """
            multiset_tbn = Tbn({
                Monomer.from_string("a* a* a* a b"): 2,
                Monomer.from_string("c"): 1,
                Monomer.from_string("2(a) b", "bob"): 5,
                Monomer.from_string("3(b) a"): 7,
                Monomer.from_string("b* 3(b) a"): 1,
            })
            self.assertEqual(multiset_tbn, Tbn.from_string(multiset_text))

        with self.subTest("testing from_string with excess monomers"):
            multiset_text = \
                """
                2[ 3(a*) a b ]
                inf[ c ]
                5[ a a b >bob ]
                inf[ b a b b ]
                b a b b b*
                """
            multiset_tbn = Tbn({
                Monomer.from_string("a* a* a* a b"): 2,
                Monomer.from_string("c"): infinity,
                Monomer.from_string("2(a) b", "bob"): 5,
                Monomer.from_string("3(b) a"): infinity,
                Monomer.from_string("b* 3(b) a"): 1,
            })
            self.assertEqual(multiset_tbn, Tbn.from_string(multiset_text))
Пример #3
0
    def test_init(self):
        for quantity in [0, -1, -2, 'a', '^', '-inf']:
            with self.subTest("Do not allow nonpositive monomer quantities", quantity=quantity):
                with self.assertRaises(AssertionError):
                    Tbn({self.x: 2, self.y: quantity})

        with self.subTest("allow infinite monomer quantities"):
            Tbn({self.x: infinity, self.y: 2})
            Tbn({self.x: 2, self.y: infinity})
Пример #4
0
    def _populate_model_from_tbn_and_polymer_basis(self, tbn: Tbn,
                                                   basis: np.array) -> None:
        self.polymer_basis = basis

        # upper bound on how many total monomers can be in non-singleton polymers
        upper_bound_on_total_monomers_in_complexes = sum(
            tbn.count(monomer_type) *
            (1 + abs(monomer_type.net_count(domain_type)))
            for monomer_type in tbn.limiting_monomer_types()
            for domain_type in tbn.limiting_domain_types())
        monomer_counts = [
            tbn.count(monomer) for monomer in tbn.monomer_types()
        ]
        upper_bound_on_total_monomers_in_complexes = min(
            upper_bound_on_total_monomers_in_complexes,
            sum(monomer_counts)  #total number of monomers
        )

        BIG_M = upper_bound_on_total_monomers_in_complexes

        self.model.set_big_m(BIG_M)

        # declare variables
        size_of_basis_vectors, number_of_basis_vectors = basis.shape
        self.basis_coefficients = [
            self.model.int_var(0, BIG_M, f"basis_coefficient_{i}")
            for i in range(number_of_basis_vectors)
        ]

        # conservation constraints
        for i, monomer_type in enumerate(list(self.tbn.monomer_types())):
            self.model.Add(
                self.tbn.count(monomer_type) == sum(
                    self.basis_coefficients[j] * basis_vector[i]
                    for j, basis_vector in enumerate(basis.T)))

        # counting constraints
        number_of_polymers = sum(self.basis_coefficients)

        if self.user_constraints.max_polymers() != infinity:
            self.model.add_constraint(
                number_of_polymers <= self.user_constraints.max_polymers())
        if self.user_constraints.min_polymers() > 0:
            self.model.add_constraint(
                number_of_polymers >= self.user_constraints.min_polymers())

        # objective function
        if self.user_constraints.optimize():
            self.model.maximize(number_of_polymers)
Пример #5
0
 def test_limiting_monomer_types(self):
     test_tbn = Tbn({
         Monomer.from_string("a b c e"): infinity,
         Monomer.from_string("a d*"): 1,
         Monomer.from_string("d*"): infinity,
         Monomer.from_string("a*"): 2,  # a* is limiting in this example
         Monomer.from_string("a d e*"): 3,  # both d and e* are limiting in this example
         Monomer.from_string("f"): 1,
         Monomer.from_string("f*"): 1,  # f* is chosen as limiting to break the tie (favors stars)
     })
     limiting_monomer_types = sorted([
         Monomer.from_string("a d e*"),
         Monomer.from_string("a*"),
         Monomer.from_string("f*")
     ])
     self.assertEqual(limiting_monomer_types, list(test_tbn.limiting_monomer_types()))
Пример #6
0
 def flatten(self) -> Tbn:
     monomer_counts = {}
     for polymer, polymer_count in self.__polymer_counts.items():
         for monomer, monomer_count in polymer.items():
             monomer_counts[monomer] = (polymer_count *
                                        monomer_count) + monomer_counts.get(
                                            monomer, 0)
     return Tbn(monomer_counts)
Пример #7
0
 def test_configs_with_number_of_polymers(self):
     test_cases = [
         # second argument is a list of number of configurations expected for specific numbers of polymers:
         #  e.g. [a,b,c,d] => 'a' configurations with 1 polymer, 'b' configurations with 2 polymers, etc., up to 4
         ("a* b* \n a b \n a* \n b*", [1, 4, 1, 0], self.cp_solver,
          SolverFormulation.BOND_OBLIVIOUS_NETWORK),
         ("a* b* \n a b \n a* \n b*", [1, 4, 1, 0], self.cp_solver,
          SolverFormulation.POLYMER_BINARY_MATRIX),
         ("a* b* \n a b \n a* \n b*", [1, 4, 1, 0], self.cp_solver,
          SolverFormulation.POLYMER_INTEGER_MATRIX),
         # recall that POLYMER_UNBOUNDED_MATRIX does not allow spurious binding of polymers without limiting monomers
         ("a* b* \n a b \n a* \n b*", [1, 3, 1, 0], self.cp_solver,
          SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
         # here VARIABLE_BOND_WEIGHT does not require saturation, hence more configurations
         ("a* b* \n a b \n a* \n b*", [1, 3, 3, 1], self.cp_solver,
          SolverFormulation.VARIABLE_BOND_WEIGHT),
         ("2[a* b*] \n a b", [1, 2, 0, 0], self.cp_solver,
          SolverFormulation.BOND_OBLIVIOUS_NETWORK),
         ("2[a* b*] \n a b", [1, 2, 0, 0], self.cp_solver,
          SolverFormulation.POLYMER_BINARY_MATRIX),
         ("2[a* b*] \n a b", [1, 1, 0, 0], self.cp_solver,
          SolverFormulation.POLYMER_INTEGER_MATRIX),
         ("2[a* b*] \n a b", [1, 1, 0, 0], self.cp_solver,
          SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
         ("2[a* b*] \n a b", [1, 1, 1, 0], self.cp_solver,
          SolverFormulation.VARIABLE_BOND_WEIGHT),
         ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", [1, 4, 0, 0],
          self.cp_solver, SolverFormulation.BOND_OBLIVIOUS_NETWORK),
         ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", [1, 4, 0, 0],
          self.cp_solver, SolverFormulation.POLYMER_BINARY_MATRIX),
         ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", [1, 3, 0, 0],
          self.cp_solver, SolverFormulation.POLYMER_INTEGER_MATRIX),
         ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", [1, 3, 0, 0],
          self.cp_solver, SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
     ]
     for tbn_string, number_of_configs_with_polymer_count, solver, formulation in test_cases:
         with self.subTest(tbn_string=tbn_string,
                           solver=solver,
                           formulation=formulation):
             test_tbn = Tbn.from_string(tbn_string)
             for polymer_count_minus_one, number_of_configs in enumerate(
                     number_of_configs_with_polymer_count):
                 polymer_count = polymer_count_minus_one + 1
                 constraints = Constraints().with_fixed_polymers(
                     polymer_count).with_unset_optimization_flag()
                 configurations = list(
                     solver.stable_configs(test_tbn,
                                           constraints,
                                           formulation=formulation))
                 self.assertEqual(number_of_configs, len(configurations))
                 for configuration in configurations:
                     self.assertEqual(polymer_count,
                                      configuration.number_of_polymers())
Пример #8
0
    def test_limiting_domain_types(self):
        tests = [
            ({}, []),
            ({self.x: 3}, [Domain("x0*"), Domain("x1*")]),
            ({self.y: 5}, [Domain("y0*"), Domain("y1*"), Domain("y2*")]),
            ({self.x: 5, self.y: 2}, [Domain("x0*"), Domain("x1*"), Domain("y0*"), Domain("y1*"), Domain("y2*")]),
            ({Monomer.from_string("a*"): 2, Monomer.from_string("a"): 1}, [Domain("a")]),
            ({Monomer.from_string("3(a*)"): 1, Monomer.from_string("a"): 2}, [Domain("a")]),
            ({Monomer.from_string("a*"): 1, Monomer.from_string("a"): 2}, [Domain("a*")]),
            ({Monomer.from_string("2(a*)"): 1, Monomer.from_string("a"): 2}, [Domain("a*")]),
            ({Monomer.from_string("2(a*)"): 1, Monomer.from_string("a"): infinity}, [Domain("a*")]),
            ({Monomer.from_string("2(a*)"): infinity, Monomer.from_string("a"): 2}, [Domain("a")]),
        ]
        for monomer_multiset, expected_limiting_domain_types in tests:
            with self.subTest("limiting domain types", tbn=str(Tbn(monomer_multiset))):
                limiting_domain_types = list(Tbn(monomer_multiset).limiting_domain_types())
                self.assertEqual(expected_limiting_domain_types, limiting_domain_types)

        with self.subTest("cannot have conflicting excess domain types"):
            conflicting_excess_tbn = Tbn(
                {Monomer.from_string("a"): infinity, Monomer.from_string("a*"): infinity}
            )
            with self.assertRaises(AssertionError):
                list(conflicting_excess_tbn.limiting_domain_types())

        with self.subTest("test equal count tie-breaking filter"):
            monomer_multiset = {
                Monomer.from_string("2(a)"): 1,
                Monomer.from_string("a*"): 2,
                Monomer.from_string("b*"): 1
            }
            limiting_domain_types = list(Tbn(monomer_multiset).limiting_domain_types(filter_ties=True))
            self.assertEqual([Domain("b")], limiting_domain_types)
Пример #9
0
    def setUp(self):
        self.x = Monomer.from_string("x0 x1", "X")
        self.y = Monomer.from_string("2(y0) 1(y1) 3(y2)", "Y")

        self.Tbn_1x = Tbn({self.x: 1})
        self.Tbn_1y = Tbn({self.y: 1})
        self.Tbn_1x_1y = Tbn({self.y: 1, self.x: 1})
        self.Tbn_2x_3y = Tbn({self.y: 3, self.x: 2})
        self.Tbn_infx_2y = Tbn({self.x: infinity, self.y: 2})
        self.Tbn_2x_infy = Tbn({self.y: infinity, self.x: 2})
        self.Tbn_1x_infy = Tbn({self.y: infinity, self.x: 1})
Пример #10
0
    def test_project_tbn_to_column_matrix(self):
        with self.subTest("slack version"):
            test_tbn = Tbn.from_string("a* b* \n a b \n a* \n b*")
            actual_matrix = Formulation._project_tbn_to_column_matrix(test_tbn)
            expected_matrix = np.array(
                [
                    [-1, -1],  # a b
                    [1, 1],  # a* b*
                    [1, 0],  # a*
                    [0, 1],  # b*
                ],
                np.int64).T
            self.assertTrue(np.array_equal(expected_matrix, actual_matrix))

        with self.subTest("no slack version"):
            test_tbn = Tbn.from_string(
                "a* b* \n a b"
            )  # no slack this time, should default to stars being limiting
            actual_matrix = Formulation._project_tbn_to_column_matrix(test_tbn)
            expected_matrix = np.array(
                [
                    [1, 1],  # a b
                    [-1, -1],  # a* b*
                ],
                np.int64).T
            self.assertTrue(np.array_equal(expected_matrix, actual_matrix))

        with self.subTest("second no slack version"):
            test_tbn = Tbn.from_string("a \n a* b* \n a b")
            actual_matrix = Formulation._project_tbn_to_column_matrix(test_tbn)
            expected_matrix = np.array(
                [
                    [1, 1],  # a b
                    [-1, -1],  # a* b*
                    [1, 0],  # a
                ],
                np.int64).T
            self.assertTrue(np.array_equal(expected_matrix, actual_matrix))
Пример #11
0
 def test_monomer_types(self):
     tests = [
         ({}, []),
         ({self.x: 3}, [self.x]),
         ({self.y: 5}, [self.y]),
         ({self.x: 5, self.y: 2}, [self.x, self.y]),
         ({self.x: infinity, self.y: infinity}, [self.x, self.y]),
     ]
     for monomer_multiset, monomer_types in tests:
         tbn = Tbn(monomer_multiset)
         with self.subTest("ordinary monomer type iterator", tbn=tbn):
             self.assertEqual(monomer_types, list(tbn.monomer_types()))
     flatten_tests = [
         ({}, []),
         ({self.x: 3}, [self.x]),
         ({self.y: 5}, [self.y]),
         ({self.x: 5, self.y: 2}, [self.x, self.y]),
     ]
     for monomer_multiset, monomer_types in flatten_tests:
         tbn = Tbn(monomer_multiset)
         with self.subTest("monomer type iterator with flatten", tbn=tbn):
             flattened_list = list(tbn.monomer_types(flatten=True))
             for monomer_type in monomer_types:
                 self.assertEqual(tbn.count(monomer_type), flattened_list.count(monomer_type))
Пример #12
0
 def test_eq(self):
     self.assertEqual(Tbn({Monomer.from_string("a"): 1}), Tbn({Monomer.from_string("a"): 1}))
     self.assertEqual(Tbn({Monomer.from_string("a"): infinity}), Tbn({Monomer.from_string("a"): infinity}))
     self.assertNotEqual(Tbn({Monomer.from_string("a"): 1}), Tbn({Monomer.from_string("a"): 2}))
     self.assertNotEqual(Tbn({Monomer.from_string("a"): 1}), Tbn({Monomer.from_string("b"): 1}))
     self.assertNotEqual(Tbn({Monomer.from_string("a"): 1}), Tbn({Monomer.from_string("a"): infinity}))
Пример #13
0
 def test_flatten(self):
     self.assertEqual(Tbn({}), Configuration({}).flatten())
     self.assertEqual(Tbn({
         self.x: 1,
         self.y: 1
     }),
                      Configuration({
                          self.polymer_1x_1y: 1
                      }).flatten())
     self.assertEqual(Tbn({
         self.x: 2,
         self.y: 3
     }),
                      Configuration({
                          self.polymer_2x_3y: 1
                      }).flatten())
     self.assertEqual(
         Tbn({
             self.x: 3,
             self.y: 4
         }),
         Configuration({
             self.polymer_1x_1y: 1,
             self.polymer_2x_3y: 1
         }).flatten())
     self.assertEqual(
         Tbn({
             self.x: 5,
             self.y: 7
         }),
         Configuration({
             self.polymer_1x_1y: 1,
             self.polymer_2x_3y: 2
         }).flatten())
     self.assertEqual(
         Tbn({
             self.x: 6,
             self.y: 8
         }),
         Configuration({
             self.polymer_1x_1y: 2,
             self.polymer_2x_3y: 2
         }).flatten())
     self.assertEqual(
         Tbn({
             self.x: 1,
             self.y: infinity
         }),
         Configuration({
             self.polymer_1x: 1,
             self.polymer_1y: infinity
         }).flatten())
     self.assertEqual(
         Tbn({
             self.x: 1,
             self.y: infinity
         }),
         Configuration({
             self.polymer_1x_1y: 1,
             self.polymer_1y: infinity
         }).flatten())
     self.assertEqual(
         Tbn({
             self.x: infinity,
             self.y: infinity
         }),
         Configuration({
             self.polymer_1x_1y: infinity,
             self.polymer_1y: 1
         }).flatten())
Пример #14
0
    def test_stable_config(self):
        test_cases = [
            ("a* b* \n a b \n a* \n b*", 3, 1, self.cp_solver,
             SolverFormulation.BOND_AWARE_NETWORK),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.cp_solver,
             SolverFormulation.BOND_OBLIVIOUS_NETWORK),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.cp_solver,
             SolverFormulation.POLYMER_BINARY_MATRIX),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.cp_solver,
             SolverFormulation.POLYMER_INTEGER_MATRIX),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.cp_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.cp_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.cp_solver,
             SolverFormulation.HILBERT_BASIS),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.ip_solver,
             SolverFormulation.BOND_AWARE_NETWORK),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.ip_solver,
             SolverFormulation.BOND_OBLIVIOUS_NETWORK),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.ip_solver,
             SolverFormulation.POLYMER_BINARY_MATRIX),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.ip_solver,
             SolverFormulation.POLYMER_INTEGER_MATRIX),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.ip_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.ip_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.ip_solver,
             SolverFormulation.HILBERT_BASIS),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver,
             SolverFormulation.BOND_AWARE_NETWORK),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver,
             SolverFormulation.BOND_OBLIVIOUS_NETWORK),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver,
             SolverFormulation.POLYMER_BINARY_MATRIX),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver,
             SolverFormulation.POLYMER_INTEGER_MATRIX),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver,
             SolverFormulation.HILBERT_BASIS),
            ("2[a* b*] \n a b", 2, 1, self.ip_solver,
             SolverFormulation.BOND_AWARE_NETWORK),
            ("2[a* b*] \n a b", 2, 1, self.ip_solver,
             SolverFormulation.BOND_OBLIVIOUS_NETWORK),
            ("2[a* b*] \n a b", 2, 1, self.ip_solver,
             SolverFormulation.POLYMER_BINARY_MATRIX),
            ("2[a* b*] \n a b", 2, 1, self.ip_solver,
             SolverFormulation.POLYMER_INTEGER_MATRIX),
            ("2[a* b*] \n a b", 2, 1, self.ip_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("2[a* b*] \n a b", 2, 1, self.ip_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("2[a* b*] \n a b", 2, 1, self.ip_solver,
             SolverFormulation.HILBERT_BASIS),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.cp_solver, SolverFormulation.BOND_OBLIVIOUS_NETWORK),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.cp_solver, SolverFormulation.POLYMER_BINARY_MATRIX),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.cp_solver, SolverFormulation.POLYMER_INTEGER_MATRIX),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.cp_solver, SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.cp_solver, SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.cp_solver, SolverFormulation.HILBERT_BASIS),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.ip_solver, SolverFormulation.BOND_OBLIVIOUS_NETWORK),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.ip_solver, SolverFormulation.POLYMER_BINARY_MATRIX),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.ip_solver, SolverFormulation.POLYMER_INTEGER_MATRIX),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.ip_solver, SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.ip_solver, SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 2, 5,
             self.ip_solver, SolverFormulation.HILBERT_BASIS),
            ("inf[a* b*] \n 2[a b]", infinity, 2, self.cp_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("inf[a* b*] \n 2[a b]", infinity, 2, self.cp_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("inf[a* b*] \n 2[a b]", infinity, 2, self.ip_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("inf[a* b*] \n 2[a b]", infinity, 2, self.ip_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", infinity, 4, self.cp_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", infinity, 4, self.cp_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", infinity, 4, self.ip_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", infinity, 4, self.ip_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
        ]
        for tbn_string, number_of_polymers, number_of_merges, solver, formulation in test_cases:
            with self.subTest(tbn_string=tbn_string,
                              solver=solver,
                              formulation=formulation):
                test_tbn = Tbn.from_string(tbn_string)
                configuration = solver.stable_config(test_tbn,
                                                     formulation=formulation,
                                                     bond_weighting_factor=2.0)
                self.assertEqual(number_of_polymers,
                                 configuration.number_of_polymers())
                self.assertEqual(number_of_merges,
                                 configuration.number_of_merges())

        low_w_test_cases = [
            ("a* b* \n a b \n a* \n b*", 4, 0, self.cp_solver, 0.4),
            ("a* b* \n a b \n a* \n b*", 4, 0, self.ip_solver, 0.4),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.cp_solver, 0.6),
            ("a* b* \n a b \n a* \n b*", 3, 1, self.ip_solver, 0.6),
            ("2[a* b*] \n a b", 3, 0, self.cp_solver, 0.4),
            ("2[a* b*] \n a b", 3, 0, self.ip_solver, 0.4),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver, 0.6),
            ("2[a* b*] \n a b", 2, 1, self.ip_solver, 0.6),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 5, 2,
             self.cp_solver, 0.4),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 5, 2,
             self.ip_solver, 0.4),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 4, 3,
             self.cp_solver, 0.6),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 4, 3,
             self.ip_solver, 0.6),
            ("inf[a* b*] \n 2[a b]", infinity, 0, self.cp_solver, 0.4),
            ("inf[a* b*] \n 2[a b]", infinity, 0, self.ip_solver, 0.4),
            ("inf[a* b*] \n 2[a b]", infinity, 2, self.cp_solver, 0.6),
            ("inf[a* b*] \n 2[a b]", infinity, 2, self.ip_solver, 0.6),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", infinity, 2, self.cp_solver,
             0.4),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", infinity, 2, self.ip_solver,
             0.4),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", infinity, 4, self.cp_solver,
             0.6),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", infinity, 4, self.ip_solver,
             0.6),
        ]

        for tbn_string, number_of_polymers, number_of_merges, solver, weight in low_w_test_cases:
            with self.subTest("low w tests",
                              tbn_string=tbn_string,
                              solver=solver,
                              weight=weight):
                test_tbn = Tbn.from_string(tbn_string)
                configuration = solver.stable_config(
                    test_tbn,
                    formulation=SolverFormulation.VARIABLE_BOND_WEIGHT,
                    bond_weighting_factor=weight,
                )
                self.assertEqual(number_of_polymers,
                                 configuration.number_of_polymers())
                self.assertEqual(number_of_merges,
                                 configuration.number_of_merges())
Пример #15
0
    def _get_hilbert_basis_from_matrix(matrix: np.array,
                                       tbn: Tbn = None,
                                       quiet: bool = False) -> np.array:
        # if a TBN is specified, the Hilbert basis will be constrained to the quantities of the monomers in the TBN
        temporary_filename_prefix = os.path.join(
            os.getcwd(), f"TEMP_4ti2_CALLOUT_{randint(0,10000)}")
        matrix_filename = temporary_filename_prefix + '.mat'
        relations_filename = temporary_filename_prefix + '.rel'
        signs_filename = temporary_filename_prefix + '.sign'
        rhs_filename = temporary_filename_prefix + '.rhs'
        homogenous_basis_filename = temporary_filename_prefix + '.zhom'
        inhomogenous_basis_filename = temporary_filename_prefix + '.zinhom'

        number_of_domain_types = matrix.shape[0]
        number_of_monomer_types = matrix.shape[1]

        if tbn:
            identity_matrix = np.identity(number_of_monomer_types, np.int64)
            matrix = np.concatenate((matrix, identity_matrix))

        # write a temporary matrix file
        with open(matrix_filename, 'w') as outFile:
            # shape is first line of the .mat file
            number_of_rows = number_of_domain_types + (number_of_monomer_types
                                                       if tbn else 0)
            outFile.write(f"{number_of_rows} {number_of_monomer_types}\n")
            for row in matrix:
                for entry in row:
                    outFile.write(f"{entry} ")
                outFile.write('\n')

        # write a temporary relations file
        with open(relations_filename, 'w') as outFile:
            entries = number_of_domain_types + (number_of_monomer_types
                                                if tbn else 0)
            outFile.write(f"1 {entries}\n")
            outFile.write(' '.join(['>'] * number_of_domain_types))
            if tbn:
                outFile.write(' ')
                outFile.write(' '.join(['<'] * number_of_monomer_types))
            outFile.write('\n')

        # write a temporary signs file
        with open(signs_filename, 'w') as outFile:
            outFile.write(f"1 {number_of_monomer_types}\n")
            outFile.write(' '.join(['1'] * number_of_monomer_types))
            outFile.write('\n')

        # write a temporary right hand sides file
        with open(rhs_filename, 'w') as outFile:
            entries = number_of_domain_types + (number_of_monomer_types
                                                if tbn else 0)
            outFile.write(f"1 {entries}\n")
            outFile.write(' '.join(['0'] * number_of_domain_types))
            if tbn:
                outFile.write(' ')
                outFile.write(' '.join([
                    str(tbn.count(monomer)) for monomer in tbn.monomer_types()
                ]))
            outFile.write('\n')

        try:
            subprocess.call(["4ti2-zsolve", temporary_filename_prefix] +
                            (['-q'] if quiet else []))

            # read and interpret response
            with open(homogenous_basis_filename, 'r') as inFile:
                # shape is first line of the file
                shape_as_string = inFile.readline()
                shape = tuple(int(x) for x in shape_as_string.split())

                flat_array = np.array(inFile.read().split(), np.int64)
                homogenous_basis = flat_array.reshape(*shape)

            with open(inhomogenous_basis_filename, 'r') as inFile:
                # shape is first line of the file
                shape_as_string = inFile.readline()
                shape = tuple(int(x) for x in shape_as_string.split())

                flat_array = np.array(inFile.read().split(), np.int64)
                inhomogenous_basis = flat_array.reshape(*shape)

                # remove the row of all zeros
                inhomogenous_basis = inhomogenous_basis[
                    ~np.all(inhomogenous_basis == 0, axis=1)]

            if homogenous_basis.size == 0:
                basis = inhomogenous_basis.T
            elif inhomogenous_basis.size == 0:
                basis = homogenous_basis.T
            else:
                basis = np.concatenate(homogenous_basis, inhomogenous_basis).T

            print('=' * 80)
            print(homogenous_basis)
            print('-' * 80)
            print(inhomogenous_basis)
            print('-' * 80)
            print(basis)
            print('=' * 80)
        except FileNotFoundError:
            print("4ti2 was not able to complete")
            basis = None
        finally:
            # clean up
            for filename in [
                    matrix_filename,
                    relations_filename,
                    signs_filename,
                    rhs_filename,
                    inhomogenous_basis_filename,
                    homogenous_basis_filename,
            ]:
                try:
                    os.remove(filename)
                except FileNotFoundError:
                    pass
        if basis.size > 0:
            return basis
        else:
            raise AssertionError(
                "the callout to 4ti2 did not generate a Hilbert basis")
Пример #16
0
    def test_stable_configs(self):
        test_cases = [
            ("a* b* \n a b \n a* \n b*", 1, 1, self.cp_solver,
             SolverFormulation.BOND_AWARE_NETWORK),
            ("a* b* \n a b \n a* \n b*", 1, 1, self.cp_solver,
             SolverFormulation.BOND_OBLIVIOUS_NETWORK),
            ("a* b* \n a b \n a* \n b*", 1, 1, self.cp_solver,
             SolverFormulation.POLYMER_BINARY_MATRIX),
            ("a* b* \n a b \n a* \n b*", 1, 1, self.cp_solver,
             SolverFormulation.POLYMER_INTEGER_MATRIX),
            ("a* b* \n a b \n a* \n b*", 1, 1, self.cp_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("a* b* \n a b \n a* \n b*", 1, 1, self.cp_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("a* b* \n a b \n a* \n b*", 1, 1, self.cp_solver,
             SolverFormulation.HILBERT_BASIS),
            ("a a \n a* a*", 2, 1, self.cp_solver,
             SolverFormulation.BOND_AWARE_NETWORK),
            ("a a \n a* a*", 1, 1, self.cp_solver,
             SolverFormulation.BOND_OBLIVIOUS_NETWORK),
            ("a a \n a* a*", 1, 1, self.cp_solver,
             SolverFormulation.POLYMER_BINARY_MATRIX),
            ("a a \n a* a*", 1, 1, self.cp_solver,
             SolverFormulation.POLYMER_INTEGER_MATRIX),
            ("a a \n a* a*", 1, 1, self.cp_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("a a \n a* a*", 1, 1, self.cp_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("a a \n a* a*", 1, 1, self.cp_solver,
             SolverFormulation.HILBERT_BASIS),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver,
             SolverFormulation.BOND_AWARE_NETWORK),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver,
             SolverFormulation.BOND_OBLIVIOUS_NETWORK),
            ("2[a* b*] \n a b", 2, 1, self.cp_solver,
             SolverFormulation.POLYMER_BINARY_MATRIX),
            ("2[a* b*] \n a b", 1, 1, self.cp_solver,
             SolverFormulation.POLYMER_INTEGER_MATRIX),
            ("2[a* b*] \n a b", 1, 1, self.cp_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("2[a* b*] \n a b", 1, 1, self.cp_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("2[a* b*] \n a b", 1, 1, self.cp_solver,
             SolverFormulation.HILBERT_BASIS),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 4, 5,
             self.cp_solver, SolverFormulation.BOND_OBLIVIOUS_NETWORK),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 4, 5,
             self.cp_solver, SolverFormulation.POLYMER_BINARY_MATRIX),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 3, 5,
             self.cp_solver, SolverFormulation.POLYMER_INTEGER_MATRIX),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 3, 5,
             self.cp_solver, SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 3, 5,
             self.cp_solver, SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 3, 5,
             self.cp_solver, SolverFormulation.HILBERT_BASIS),
            ("inf[a* b*] \n 2[a b]", 1, 2, self.cp_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("inf[a* b*] \n 2[a b]", 1, 2, self.cp_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", 2, 4, self.cp_solver,
             SolverFormulation.POLYMER_UNBOUNDED_MATRIX),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", 2, 4, self.cp_solver,
             SolverFormulation.VARIABLE_BOND_WEIGHT),
        ]
        for tbn_string, number_of_configs, number_of_merges, solver, formulation in test_cases:
            with self.subTest(tbn_string=tbn_string,
                              solver=solver,
                              formulation=formulation):
                test_tbn = Tbn.from_string(tbn_string)
                configurations = list(
                    solver.stable_configs(test_tbn,
                                          formulation=formulation,
                                          bond_weighting_factor=2.0))
                self.assertEqual(number_of_configs, len(configurations))
                for configuration in configurations:
                    self.assertEqual(number_of_merges,
                                     configuration.number_of_merges())

        low_w_test_cases = [
            ("a* b* \n a b \n a* \n b*", 1, 0.8, self.cp_solver, 0.4),
            ("a* b* \n a b \n a* \n b*", 1, 1.0, self.cp_solver, 0.6),
            ("2[a* b*] \n a b", 1, 0.8, self.cp_solver, 0.4),
            ("2[a* b*] \n a b", 1, 1.0, self.cp_solver, 0.6),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 1, 3.6,
             self.cp_solver, 0.4),
            ("6(a*) \n 2[3(a*)] \n a \n 5(a) \n 2(a) \n 4(a)", 1, 4.2,
             self.cp_solver, 0.6),
            ("inf[a* b*] \n 2[a b]", 1, 1.6, self.cp_solver, 0.4),
            ("inf[a* b*] \n 2[a b]", 1, 2.0, self.cp_solver, 0.6),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", 1, 3.6, self.cp_solver, 0.4),
            ("inf[2(a*) 2(b*)] \n 2[3(a) 3(b)]", 2, 4.0, self.cp_solver, 0.6),
        ]

        for tbn_string, number_of_configs, energy, solver, weight in low_w_test_cases:
            with self.subTest("low w tests",
                              tbn_string=tbn_string,
                              solver=solver,
                              weight=weight):
                test_tbn = Tbn.from_string(tbn_string)
                configurations = list(
                    solver.stable_configs(
                        test_tbn,
                        formulation=SolverFormulation.VARIABLE_BOND_WEIGHT,
                        bond_weighting_factor=weight,
                    ))
                self.assertEqual(number_of_configs, len(configurations))
                for configuration in configurations:
                    self.assertEqual(energy, configuration.energy(weight))
Пример #17
0
def get_tbn_from_filename(tbn_filename) -> Tbn:
    with open(tbn_filename) as tbnFile:
        tbn_as_string = tbnFile.read()

    return Tbn.from_string(tbn_as_string)