def test_init(self): with self.subTest( "Do not allow monomers in the configuration -- only polymers"): with self.assertRaises(AssertionError): Configuration({self.polymer_1x: 1, self.y: 1}) with self.assertRaises(AssertionError): Configuration({self.x: 1, self.polymer_1y: 1}) with self.subTest( "Do not allow domains in the configuration -- only polymers"): with self.assertRaises(AssertionError): Configuration({self.polymer_1x: 1, Domain("y"): 1}) with self.assertRaises(AssertionError): Configuration({Domain("x"): 1, self.polymer_1y: 1}) with self.subTest("Allow multiple of same type of polymer"): test_configuration = Configuration({ self.polymer_1x: 1, self.polymer_1y: 2 }) self.assertTrue(3, test_configuration.number_of_polymers()) with self.subTest("Allow infinite quantities of polymers"): test_configuration = Configuration({ self.polymer_1x: infinity, self.polymer_1y: 2 }) self.assertTrue(infinity, test_configuration.number_of_polymers())
def test_net_count(self): tests = [ (self.x, "x0", 1), (self.x, "x1", 1), (self.x, "x2", 0), (self.x, "x0*", -1), (self.x, "x1*", -1), (self.x, "x2*", 0), (self.y, "y0", 2), (self.y, "y1", 1), (self.y, "y2", 3), (self.y, "y0*", -2), (self.y, "y1*", -1), (self.y, "y2*", -3), (self.abc_star, "a", 1), (self.abc_star, "b", 1), (self.abc_star, "c", -1), (self.triple_a_star, "a", -3), (self.triple_a_star, "a*", 3), (self.semi_self_saturated_monomer, "a", 0), (self.semi_self_saturated_monomer, "b", 1), (self.semi_self_saturated_monomer, "a*", 0), (self.semi_self_saturated_monomer, "b*", -1), ] for monomer, domain_string, net_count in tests: with self.subTest("net count", monomer=str(monomer), domain=domain_string, net_count=net_count): self.assertEqual(net_count, monomer.net_count(Domain(domain_string)))
def test_init(self): for quantity in [0, -1, -2, 'a', '^', float("inf")]: with self.subTest( "Do not allow nonpositive or infinite domain quantities", quantity=quantity): with self.assertRaises(AssertionError): Monomer({ Domain("xx"): 2, Domain("yy"): quantity }, "bad_monomer") with self.subTest("Do not allow empty monomers"): with self.assertRaises(AssertionError): Monomer.from_string("") with self.assertRaises(AssertionError): Monomer.from_string(">empty_monomer") for name in ["X", "Y"]: with self.subTest("No duplicate names", name=name): with self.assertRaises(AssertionError): Monomer.from_string(f"z0 z1 >{name}") with self.subTest("Accept duplicate monomer name if domains match"): Monomer.from_string("x0 x1 >X") Monomer.from_string("2(y0) 1(y1) 3(y2) >Y") Monomer.from_string("2(y0) y1 3(y2) >Y") with self.subTest( "Accept duplicate monomer name if domains match but are switched" ): Monomer.from_string("x1 x0 >X") Monomer.from_string("1(y1) 2(y0) 3(y2) >Y") Monomer.from_string("y1 2(y0) 3(y2) >Y") Monomer.from_string("c* a b") Monomer.from_string("a b a* b b*") with self.subTest( "Do not collapse complements; e.g. do not annihilate a with a*" ): Monomer.from_string("b") Monomer.from_string("a a* b")
def from_string(cls, monomer_as_string: str, name: str = None) -> "Monomer": # name extraction first domain_list_regex = f"{cls.multiple_domain_regex}(?: {cls.multiple_domain_regex})*" name_search_pattern = f"^({domain_list_regex})\\s*(|>{cls.name_regex})$" name_search_result = re.match(name_search_pattern, monomer_as_string) if not name_search_result: raise AssertionError( f"could not parse monomer from string '{monomer_as_string}'") composition_string, raw_name_string = name_search_result.groups() if raw_name_string: if name: raise AssertionError( "received call to Monomer.from_string() specifying a name in the string and in the passed argument" ) else: name = raw_name_string[1:] # remove the '>' # now parse the composition of the monomer domain_counts = {} domain_strings_as_list = composition_string.split() for domain_string_with_optional_quantity in domain_strings_as_list: quantity_search_result = re.match( f"^([1-9]\\d*)\\(\\s*({Domain.regex()})\\s*\\)$", domain_string_with_optional_quantity) if quantity_search_result: count = int(quantity_search_result.groups()[0]) domain_string = quantity_search_result.groups()[1] else: count = 1 domain_string = domain_string_with_optional_quantity domain_search_result = re.match(f"^({Domain.regex()})$", domain_string) if not domain_search_result: raise AssertionError( f"Could not parse domain name from {domain_search_result}") domain = Domain(domain_search_result.groups()[0]) domain_counts[domain] = domain_counts.get(domain, 0) + count return cls(domain_counts, name)
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)
def net_count(self, domain: Domain) -> int: return self.__domain_counts.get(domain, 0) - self.__domain_counts.get( domain.complement(), 0)
import os from telegram.ext import Updater, CommandHandler, MessageHandler, Filters from easy_botan import Botan from source.setting import Setting from source.domain import Domain APP_ID = 'IceMkbBot' setting = Setting(os.path.dirname(__file__)) domain = Domain(setting) botan = Botan(setting) def cm_start(bot, update): domain.on_start(bot, update) botan.track(update.message, 'start') def cm_about(bot, update): domain.on_about(bot, update) botan.track(update.message, 'about') def cm_help(bot, update): domain.on_next_item(bot, update) botan.track(update.message, 'next') def callb_text(bot, update): try: log_msg = domain.on_text(bot, update) botan.track(update.message, log_msg) except BaseException as e: print(e)
def test_as_explicit_list(self): self.assertEqual([Domain("x0"), Domain("x1")], self.x.as_explicit_list()) self.assertEqual([ Domain("y0"), Domain("y0"), Domain("y1"), Domain("y2"), Domain("y2"), Domain("y2") ], self.y.as_explicit_list()) self.assertEqual( [Domain("a"), Domain("b"), Domain("c*")], self.abc_star.as_explicit_list()) self.assertEqual( [Domain("a*"), Domain("a*"), Domain("a*")], self.triple_a_star.as_explicit_list()) self.assertEqual([ Domain("a"), Domain("a*"), Domain("b"), Domain("b"), Domain("b*") ], self.semi_self_saturated_monomer.as_explicit_list())
def test_unstarred_domain_types(self): tests = [ (self.x, [Domain("x0"), Domain("x1")]), (self.y, [Domain("y0"), Domain("y1"), Domain("y2")]), (self.abc_star, [Domain("a"), Domain("b"), Domain("c")]), (self.triple_a_star, [Domain("a")]), (self.semi_self_saturated_monomer, [Domain("a"), Domain("b")]), ] for monomer, unstarred_domain_types in tests: with self.subTest("must return unstarred domain types", monomer=str(monomer)): self.assertEqual(unstarred_domain_types, list(monomer.unstarred_domain_types()))
def test_from_string(self): class SensingMonomer(Monomer): def __init__(self, sensed_domain_multiset: Dict[Domain, int], sensed_name: str): super().__init__(sensed_domain_multiset, sensed_name) self.sensed_domain_multiset = sensed_domain_multiset self.sensed_name = sensed_name a = Domain("a") a_star = a.complement() b = Domain("b") b_star = b.complement() tests = [ ({ a: 2, b: 3, b_star: 1 }, "aabbb_star"), ({ a: 1, b_star: 1 }, "ab_star"), ({ a: 3, b_star: 1 }, "aaab_star"), ] for domain_multiset, name in tests: domain_multiset_as_string = " ".join([ " ".join(count * [str(domain)]) for domain, count in domain_multiset.items() ]) with self.subTest( "from_string() correctly parses and sends to __init__()"): created_monomer = SensingMonomer.from_string( f"{domain_multiset_as_string} >{name}") self.assertEqual(domain_multiset, created_monomer.sensed_domain_multiset) self.assertEqual(name, created_monomer.sensed_name) with self.subTest( "from_string() correctly defaults to 'None' when no name is provided" ): unnamed_monomer = SensingMonomer.from_string( domain_multiset_as_string) self.assertEqual(None, unnamed_monomer.sensed_name) with self.subTest("correctly collapses to multiset"): new_monomer = SensingMonomer.from_string("a a a b a*") self.assertEqual({ a: 3, a_star: 1, b: 1 }, new_monomer.sensed_domain_multiset) with self.subTest("ignores legacy domain names appearing after colon"): legacy_monomer = SensingMonomer.from_string("a a:name a* b:name2") self.assertEqual({ a: 2, a_star: 1, b: 1 }, legacy_monomer.sensed_domain_multiset)